Programación de microcontroladores vs programación orientada a objetos

Hice algo de programación básica orientada a objetos con C ++ (creación de un árbol B, algoritmos hash, listas de doble enlace) y hice un pequeño proyecto en C (como hacer una calculadora científica, etc.)

¿Qué tan diferente es la programación de hardware (específicamente para microcontroladores) de la programación orientada a objetos/software en términos de mentalidad y "pensamiento" que debe tener el programador?

¿Se suele considerar que uno es más difícil que el otro para la mayoría de la gente?

Con mi experiencia (como se describe anteriormente), ¿necesitaría mucha preparación para ingresar a la programación de hardware o puedo sumergirme directamente sin demasiada preparación?

La mayor curva de aprendizaje será cómo controlar el hardware específico de su micro. Eso implicará estudiar detenidamente las hojas de datos durante horas. Desafortunadamente, no hay una salida fácil.
@rrazd, noté que incluiste la etiqueta arduino. ¿Es esto porque desea utilizar el lenguaje de cableado y las bibliotecas de arduino? ¿O escribirá sus aplicaciones integradas en C puro? Si tiene la intención de seguir con el entorno arduino, es bastante seguro y fácil de jugar, ya que han hecho algunas abstracciones fuera del hardware.
@Jon planeo usar una placa arduino para empezar. ¿No es similar al lenguaje C? Pensé que involucraba los mismos conceptos básicos....
Me pregunto si te refieres a lo que muchas personas llamarían 'programación de E/S', o si anticipas reorganizar el hardware con código. El arduino es decididamente el primero; este último sería el dominio de los FPGA.
@rrazd, he decidido convertir mi respuesta a tu último comentario en una respuesta. Vea abajo.
Me doy cuenta de que debería estar haciendo una pregunta igual pero opuesta, ya que vengo del hardware y ahora necesito asimilar profundamente OO
@rrazd: cambié el título; "programación de hardware" se parece demasiado a HDL (lenguaje de descripción de hardware), por ejemplo, VHDL y Verilog, que se utilizan para programar FPGA y CPLD.

Respuestas (7)

Tendrá que abandonar por completo el paradigma orientado a objetos cuando trabaje con la mayoría de los microcontroladores.

Los microcontroladores generalmente están limitados por el registro y la RAM, con frecuencias de reloj lentas y sin rutas de código en paralelo/canalización. Puedes olvidarte de Java en un PIC, por ejemplo.

Tienes que entrar en una mentalidad de lenguaje ensamblador y escribir procedimentalmente.

Debe mantener su código relativamente plano y evitar la recursividad, ya que las limitaciones de RAM a menudo pueden generar problemas de pila.

Debe aprender a escribir rutinas de servicio de interrupción que sean eficientes (generalmente en lenguaje ensamblador).

Es posible que deba refactorizar partes del código manualmente, en lenguaje ensamblador, para implementar la funcionalidad que el compilador no admite (o admite deficientemente).

Debe escribir un código matemático que tenga en cuenta el tamaño de palabra y la falta de capacidades de FPU de la mayoría de los microcontroladores (es decir, hacer una multiplicación de 32 bits en un micro de 8 bits = malvado).

Es un mundo diferente. Para mí, tener experiencia en informática o programación profesional puede ser un obstáculo tan grande como no tener ningún conocimiento cuando se trata de microcontroladores.

No tiene que abandonar por completo el paradigma orientado a objetos, pero en micros más pequeños puede ser necesario abandonar las implementaciones de objetos pesados ​​y realmente pensar cuál es la mejor manera de resolver cada problema. A menudo, eso es un procedimiento, pero los objetos livianos, bien implementados (generalmente a mano), a veces pueden reducir el tamaño de proyectos de microcontroladores complicados.
Todo esto es cierto excepto abandonar la orientación a objetos. Probablemente no utilice un lenguaje con características OO, pero eso no descarta la orientación a objetos. Para los microcontroladores, escribirá controladores para todos los periféricos de hardware (ADC, controladores de bus serie, PWM, etc., etc.). Dicho controlador siempre debe escribirse de manera orientada a objetos para que sea 1) autónomo y no sepa/no se preocupe por el resto del programa, y ​​2) implemente una encapsulación privada para que el resto del programa no pueda entrar y jugar con él. Esto es 100% posible en C y no afectará el rendimiento.
Estoy totalmente en desacuerdo con la primera oración, todos mis proyectos de microcontroladores fueron construidos con C++ y un enfoque orientado a objetos, y los micros que usamos no eran muy grandes (32kB de ROM), el cargador de arranque también orientado a objetos estaba en menos de 2kB, yo Realmente no veo limitación. No puedes hacer locuras, pero el diseño puede estar orientado a objetos sin problema.
@Arsenal Tenga en cuenta que dije 'la mayoría' y tenga en cuenta que está comentando un hilo de cuatro años. :)
Estoy totalmente en desacuerdo con la primera y la última oración. Y también el ensamblaje se usa muy raramente y, en su mayoría, solo para MCU de 8 bits (solo consulte este foro, ¿cuántas publicaciones con código ensamblador puede encontrar?). Ciertamente puede y (en mi humilde opinión) debe escribir en estilo OO para MCU de 32 bits

Tienes que pensar en varias cosas:

  • Usarás C como lenguaje
  • Todavía puede crear una sensación de orientación a objetos usando punteros de función para que pueda anular funciones, etc. He usado este método en proyectos pasados ​​y actuales y funciona muy bien. Entonces OO está parcialmente allí pero no en el sentido de C++.

Hay otras limitaciones que entrarán en juego, como la velocidad y la memoria limitadas. Entonces, como pauta general, evito:

  • Usando heap, si hay una manera de resolver el problema sin Malloc, lo hago. Por ejemplo, preasigno búferes y simplemente los uso.
  • Reduzco intencionalmente el tamaño de la pila en la configuración del compilador para enfrentar los problemas de tamaño de la pila desde el principio, optimícelo con cuidado.
  • Supongo que cada línea de código se verá interrumpida por un evento, por lo que evito el código que no vuelve a entrar
  • Supongo que incluso las interrupciones están anidadas, así que escribo ese código en consecuencia.
  • Evito usar el sistema operativo a menos que sea necesario. El 70% de los proyectos integrados realmente no necesitan un sistema operativo. Si debo usar un sistema operativo, solo uso algo con código fuente disponible. (Freertos etc)
  • si estoy usando un sistema operativo, casi siempre abstraigo cosas para poder cambiar el sistema operativo en cuestión de horas.
  • Para los controladores, etc., solo usaré las bibliotecas proporcionadas por el proveedor, nunca manipularé los bits directamente, a menos que no tenga otra opción. Esto hace que el código sea legible y mejora la depuración.
  • Miro los bucles y otras cosas, especialmente en ISR, para asegurarme de que sean lo suficientemente rápidos.
  • Siempre tengo algunos GPIO a mano para medir cosas, cambiar de contexto, tiempo de ejecución de ISR, etc.

La lista continúa, probablemente estoy por debajo del promedio en términos de programación de software, estoy seguro de que hay mejores prácticas.

+1 para "puedes usar paradigmas OO si quieres". Lo que debe verificar en la puerta no es un diseño OO. OOD es solo una filosofía que lo alienta a mantener juntos el código y los datos relacionados. Lo que debe dejar atrás es la forma en que se implementa OO en los sistemas empresariales, con múltiples capas de abstracción, inversión de control y todo ese jazz. La tarea de su firmware es controlar el hardware, eso es todo.

Hago ambas cosas, así que aquí está mi punto de vista.

Creo que la habilidad más importante con diferencia en Embedded es tu capacidad de depuración. La mentalidad requerida es muy diferente en el sentido de que muchas cosas pueden salir mal, y debe estar muy abierto a considerar todas las diferentes formas en que lo que está tratando de hacer puede salir mal.

Este es el mayor problema para los nuevos desarrolladores integrados. La gente de PC tiende a tenerlo más duro, ya que están acostumbrados a trabajar para ellos. Tienden a perder mucho tiempo buscando herramientas para hacer cosas por ellos (pista: no hay muchas). Hay muchos golpes de cabeza contra las paredes una y otra vez, sin saber qué más hacer. Si siente que se está atascando, dé un paso atrás y averigüe si puede identificar qué es lo que podría estar saliendo mal. Reduzca sistemáticamente su lista de problemas potenciales hasta que lo descubra. Se sigue directamente de este proceso que debe limitar el alcance de los problemas al no cambiar demasiado a la vez.

Las personas integradas con experiencia tienden a dar por sentada la depuración... la mayoría de las personas que no pueden hacerlo bien no duran mucho (o trabajan en grandes empresas que simplemente aceptan que "el firmware es difícil" como respuesta a por qué una característica determinada tiene años de retraso)

Está trabajando en un código que se ejecuta en un sistema externo a su sistema de desarrollo, con distintos grados de visibilidad en su objetivo de una plataforma a otra. Si está bajo su control, busque ayudas de desarrollo para ayudar a aumentar esta visibilidad en su sistema de destino. Use puertos serie de depuración, salida de depuración de golpes de bits, la famosa luz parpadeante, etc. Sin duda, como mínimo, aprenda a usar un osciloscopio y use E / S de pines con el alcance para ver cuándo entran / salen ciertas funciones, se disparan los ISR, etc. He visto a personas luchar literalmente durante años más de lo necesario simplemente porque nunca se molestaron en configurar/aprender a usar un enlace de depurador JTAG adecuado.

Es mucho más importante ser muy consciente de exactamente qué recursos tiene en relación con una PC. Lea atentamente las hojas de datos. Considere el 'costo' de recursos de cualquier cosa que esté tratando de hacer. Aprenda trucos de depuración orientados a los recursos, como llenar el espacio de la pila con un valor mágico para realizar un seguimiento del uso de la pila.

Si bien se requiere cierto grado de habilidad de depuración tanto para la PC como para el software integrado, es mucho más importante con el software integrado.

Supongo que su experiencia con C++ está basada en PC.

Un error que a menudo cometen los programadores que pasan de una PC a un microcontrolador es que no se dan cuenta de lo limitados que pueden ser los recursos. En una PC, nadie lo detendrá cuando cree una tabla con 100 000 entradas o escriba un programa que compile en 1 MB de código de máquina.
Hay microcontroladores que tienen una gran cantidad de recursos de memoria, especialmente en el extremo superior, pero aún está muy lejos de lo que estará acostumbrado. Para un proyecto de afición, probablemente siempre puedas aprovechar al máximo, pero en un proyecto profesional, a menudo te verás obligado a trabajar con el dispositivo más pequeño porque es más barato .
En un proyecto estaba trabajando con un TI MSP430F1101. 1KB de memoria de programa, 128 bytes de configuración Flash, 128 bytes de RAM. El programa no entraba en el 1K, así que tuve que escribir una función de 23 bytes en la configuración Flash. Con estos pequeños controladores calculas por bytes . En otra ocasión, la memoria del programa era 4 bytes demasiado pequeña. Boss no me dejaba usar el controlador con más memoria, sino que tenía que optimizar un código de máquina ya optimizado (ya estaba escrito en ensamblador) para que cupieran los 4 bytes adicionales. Te haces una idea.

Dependiendo de la plataforma en la que esté trabajando, tendrá que lidiar con E/S de muy bajo nivel . Algunos entornos de desarrollo tienen funciones para escribir en una pantalla LCD, pero en otros estás solo y tendrás que leer la hoja de datos de la pantalla LCD de principio a fin para saber cómo controlarla.
Es posible que deba controlar un relé, que es más fácil que una pantalla LCD, pero requerirá que vaya al nivel de registro del microcontrolador. Nuevamente una hoja de datos o manual de usuario. Tendrá que familiarizarse con la estructura del microcontrolador, que encontrará en un diagrama de bloques, nuevamente en la hoja de datos. En la época del microprocesador hablábamos de un modelo de programación, que era básicamente una alineación de los registros del procesador. Los microcontroladores actuales son tan complejos que una descripción de todos los registros puede ocupar la mayor parte de una hoja de datos de 100 páginas. IIRC solo la descripción del módulo de reloj para el MSP430 tenía 25 páginas.

A menudo tendrá que lidiar con el manejo de eventos en tiempo real . Una interrupción que tienes que manejar dentro de 10 m s, por ejemplo, y durante eso tienen otra interrupción que requiere la misma precisión de tiempo.

Los microcontroladores a menudo se programan en C. C++ tiene bastante hambre de recursos, por lo que generalmente está fuera. (La mayoría de las implementaciones de C ++ para microcontroladores ofrecen un subconjunto limitado de C ++). Como dije, dependiendo de la plataforma, es posible que tenga una amplia biblioteca de funciones disponibles que podrían ahorrarle bastante tiempo de desarrollo. Vale la pena tomarse un tiempo para estudiarlo, puede ahorrarle mucho tiempo más adelante si sabe lo que está disponible.

He escrito juegos para Atari 2600, que es una plataforma bastante limitada; mi primer juego publicado fue esencialmente código 4K (dado que tenía un carrito de 32K, agregué algunos extras, pero la versión 4K era totalmente jugable); La RAM es de 128 bytes. Me parece interesante contemplar que en el año en que escribí ese juego (2005), se publicaron otros juegos que eran, literalmente, un millón de veces más grandes.
@supercat - Sí, pero eso era de esperar, ¡en 2005 el Atari 2600 ya tenía 200 años! Nunca he jugado juegos de acción como los FPS, pero cuando miro lo que se necesita para jugarlos, una GPU mucho más poderosa que tu CPU, tanto programática como eléctricamente, no puedo evitar negar con la cabeza :-). Jugué al ajedrez (Sargon) en un 16k TRS-80 IIRC. El Flight Simulator de mi hermano no necesitaba más.
No llega a los 200 años. Debutó en 1977, por lo que ni siquiera tenía 30. Si bien estoy de acuerdo en que eso fue hace eones en términos tecnológicos, todavía estoy impresionado por el hecho de que no hay solo un aumento de cien, ni un aumento de mil veces. , pero un aumento de MILLONES de veces tanto en RAM como en tamaño de código. La velocidad no ha aumentado tanto, ya que el 2600 era de 1,19 MHz y los sistemas más nuevos solo están en el rango bajo de GHz. Pueden hacer mucho más por ciclo que el 2600 (que podía, y tenía que, generar 1/76 de una línea de video en cada ciclo), pero no creo que sean 1,000,000 veces más rápidos.

"programación de hardware" puede significar muchas cosas. Programar un chip muy pequeño (piense en 10F200, 512 instrucciones, unos pocos bytes de RAM) puede ser casi como diseñar un circuito electrónico. Por otro lado, la programación de un gran microcontrolador Cortex (FLASH de 1 Mb, RAM de 64 kB) puede ser muy parecida a la programación de PC/GUI, utilizando un gran conjunto de herramientas de GUI. En mi humilde opinión, un buen programador integrado/en tiempo real necesita habilidades tanto desde el lado de la ingeniería de software como desde el lado del diseño del circuito. Para los uC más grandes, C++ es una buena opción de lenguaje, para los muy pequeños, C podría ser la única opción. El conocimiento de ensamblaje puede ser útil, pero no recomendaría hacer proyectos serios completamente en ensamblaje.

He realizado un trabajo integrado serio con personas de ambos lados (SWI y EE). En general, prefiero a la gente de SWI, siempre que tengan algo de experiencia con la programación multihilo.

Su pregunta suena como si quisiera sumergirse en la programación integrada. Por todos los medios hazlo. Para los aspectos de bajo nivel (interconectar los periféricos en su chip y el hardware que lo rodea), necesitará aprender algunas habilidades nuevas, pero es mucho trabajo sin muchos conceptos nuevos. Para las capas superiores de sus proyectos, puede basarse en su conocimiento existente.

Para cada método de biblioteca de arduino al que llama, hay una gran cantidad de código C/C++ que lo hace posible, simplemente está empaquetado muy bien para que lo use como una API. Eche un vistazo al código fuente de arduino en el directorio hardware/arduino/* y verá todo el C/C++ escrito para usted que interactúa directamente con los registros del microcontrolador AVR. Si su objetivo es aprender a escribir cosas como esta (directamente para el hardware), entonces hay mucho que cubrir. Si su objetivo es hacer que algo funcione usando sus bibliotecas, entonces puede que no haya mucho de qué hablar, ya que la mayor parte del trabajo duro lo hace usted y sus bibliotecas y el entorno de desarrollo son muy fáciles de usar.

Sin embargo, algunas reglas generales cuando se trabaja con dispositivos con recursos limitados que podrían aplicarse al entorno arduino u otros:

Tenga en cuenta la cantidad de memoria que está utilizando. Tanto el tamaño del código (que va a la memoria flash) como el uso de RAM estática (constantes en su código que siempre existirán en la RAM). Yo diría que el uso de RAM estática es un poco más importante al principio, ya que es fácil pasarlo por alto. No es raro que tenga solo 1000 bytes para trabajar con su pila, montón y constantes. Sea prudente en la forma en que lo gasta, así que evite cosas como largas matrices de números enteros (4 bytes cada uno) cuando los bytes o los caracteres sin signo (1 byte cada uno) serán suficientes. Otra respuesta aquí cubre muy bien algunos otros puntos importantes, así que me detendré aquí, principalmente quería transmitir el punto de que hay mucho que cubrir si no está usando la biblioteca arduino y escribiendo sus propias bibliotecas C.

En cuanto a la programación de microcontroladores vs OOP, no son algo opuesto. Es cierto que todas las bibliotecas de proveedores están en C simple, pero todas las plataformas también admiten C++ OOP. Los desarrolladores pueden crear y crear bibliotecas de alto nivel de C++ y firmware de dispositivos además de eso. El buen ejemplo son las bibliotecas Arduino, oficiales y creadas por el usuario, en su mayoría clases de C ++. Tal vez no todas las ventajas de OOP se puedan utilizar por completo en un entorno integrado, pero las conocidas ventajas de C ++ frente a C también son válidas aquí.

Con respecto a la mentalidad y el pensamiento, como se señaló en otras respuestas, los microcontroladores son plataformas con recursos muy limitados (especialmente en RAM, menos en velocidad), cosas como la asignación dinámica de memoria, las excepciones de C ++ generalmente se descartan. Dado que se elige el hardware adecuado, es fácil adoptar estas limitaciones y utilizar otras técnicas (también muy utilizadas en otras plataformas).

En mi opinión, el desafío más difícil podría ser una dimensión adicional más que se encuentra en la programación integrada: el tiempo. Esto se debe a que, por lo general, el software integrado trata mucho con eventos en tiempo real, protocolos estrictamente cronometrados para controlar el hardware periférico y la tarea general en sí misma (estos también son algunos paralelos en otras plataformas de "alto nivel", como aplicaciones de subprocesos múltiples).

Esté preparado para leer muchas hojas de datos cuando se trata de hardware nuevo; supongo que podría estar relacionado con la parte de la pregunta de "mentalidad" :) Seguramente se necesitaría algún conocimiento de hardware y EE.

También me gustaría señalar que en estos días el desarrollo de software integrado no requiere lenguaje ensamblador. De hecho, Java (por cierto, es OOP por defecto) ya está aquí y se está volviendo más fuerte (al menos para alguna clase de dispositivos integrados, por ejemplo, dispositivos IoT, podría tener un futuro muy brillante).

En términos de preocupaciones, aquellas relacionadas con la (re)asignación de memoria dinámica tienden a ser un impedimento mayor para el OO tradicional que el tiempo .
Quizás estás en lo cierto. Pero hay personas que programaron en los años 80-90 para el software de modo real de MSDOS, con 64K (segmento de memoria de datos) de espacio RAM disponible y para ellos era "natural". Tal vez MSDOS PC era un entorno más "incrustado" que el STM32F4 actual :)
El STM32F4 generalmente tiene más memoria de programa en forma de flash, pero la PC generalmente viene con mucha más memoria RAM para almacenar objetos de tiempo de ejecución mutables. Si bien todo el asunto del puntero lejano forzado por el direccionamiento segmentado fue un dolor, ambos carecen de una verdadera MMU, y eso será aún más preocupante en el sistema con menos RAM, que es el STM32F4. Además, los tiempos de actividad de las PC tendían a ser más cortos y las tasas de fallas aceptables eran más altas.