¿Funcionará el mismo código C para un microcontrolador AVR con cualquier otro tipo?

Estoy aprendiendo sobre microcontroladores y tengo un conocimiento muy limitado sobre el tema.

Solo sé que uno necesita establecer bits en los registros y manipularlos básicamente para que funcione un uC. Los registros configuran y controlan la electrónica en el microcontrolador.

Digamos que escribí un código C en Atmel Studio para un uC de 8 bits en particular. Este uC tiene nombres de registro en su hoja de datos como TCNT0 por ejemplo. ¿Qué pasa si quiero usar el mismo código con otro AVR de 8 bits? ¿Debo escribir todo desde cero o solo necesito hacer pequeñas modificaciones? ¿La mayoría de los nombres de registro son comunes?

Por ejemplo, si programo un ATmega328P con C, ¿funcionaría el mismo código en cualquier otro tipo de 8 bits, por ejemplo, con ATmega168? Y si no, ¿normalmente lo escribirías desde cero o simplemente modificarías el anterior?

Estoy confundido acerca de la compatibilidad del código. ¿Qué tal la misma pregunta para usar el código de uC de 8 bits para un uC de 32 bits como AVR32?

el problema es que un porcentaje del código y/o las bibliotecas son puros y se comunican con periféricos y direcciones específicos en el chip. No hay razón para suponer que desde un chip de la misma familia hasta familias de chips o compañías completamente diferentes tengan la misma cantidad de periféricos que son idénticos en diseño y tienen la misma dirección. Es posible crear un entorno para intentar aumentar la portabilidad (arduino, mbed) pero aún no puede pedir cosas que el chip en el que está no tiene o si no hay una biblioteca para ese chip, entonces no.
cuando se llaman registros específicos, es posible que ni siquiera se transfiera a toda la familia. Tienes que inspeccionar las dos hojas de datos.

Respuestas (6)

Por ejemplo, si programo un ATmega328P con C, ¿funcionaría el mismo código en cualquier otro tipo de 8 bits, por ejemplo, con ATmega168?

En ese caso, la respuesta pasa a ser sí. La única diferencia entre el ATmega168P y el 328P es la cantidad de memoria flash, siempre que su programa quepa en el 168P (es decir, siempre que no supere los 16 KB), se ejecutará de manera idéntica en esa parte.

En otros casos… depende. Hay algunas diferencias sutiles en los periféricos y las características de la línea AVR, incluso en situaciones en las que los periféricos tienen el mismo nombre. Compare las hojas de datos cuidadosamente para obtener más detalles.

¿Qué tal la misma pregunta para usar el código de uC de 8 bits para un uC de 32 bits como AVR32?

AVR32 es una arquitectura completamente diferente de AVR de 8 bits; no tienen casi nada en común además del nombre. Así que probablemente tendrías que reescribir tu programa.

En el nivel C, no es tan diferente como parece, pero en el nivel C, el código para un programa completo de Unix no es tan diferente . Lo que es significativamente diferente entre las arquitecturas AVR es el conjunto de instrucciones, el mapa de memoria y los periféricos, básicamente todo. Pero C sigue siendo C independientemente.

El código se puede escribir para que sea portátil entre microcontroladores. Es una buena idea hacer esto a menos que su aplicación sea muy simple o tenga mucha prisa :)

La idea es separar los procedimientos de nivel superior (su flujo de programa principal) de la manipulación de hardware de bajo nivel (encender pines, configurar registros, etc.).

Para un ejemplo simple, tome un circuito en el que desee controlar un LED. Puede configurar su código teniendo un módulo completamente separado para los LED: (No trabajo con AVR; perdone cualquier error)

led.c:

// For simplicity, this assumes all LEDs are on Port D.

void ledInit(uint8_t ledPin)
{

    DDRD |= (1 << ledPin);   // Configure the pin as an output
    PORTD &= ~(1 << ledPin); // Set the pin low
}

void ledOn(uint8_t ledPin)
{
    PORTD |= (1 << ledPin);
}

void ledOff(uint8_t ledPin)
{
    PORTD &= ~(1 << ledPin);
}

Luego, en su código de línea principal, solo accedería al LED a través de estos comandos. Si necesita más acceso, como un comando de alternar, lo agregaría al archivo led.c. El código principal ni siquiera es consciente de lo que sucede dentro del módulo LED.

Esto hace que sea mucho más fácil mover su código de línea principal entre microcontroladores. Básicamente, solo necesitaría volver a escribir el archivo led.c. No tendría que cambiar su código de línea principal en absoluto .

Esta lógica también se puede utilizar para temporizadores, puertos de comunicaciones (SPI, I2C, USART...), etc.


En un proyecto grande, me parece mejor tener tres capas de código:

  • El código principal, que orquesta todo
  • Nivel medio, que proporciona funciones y nombres (#defines) al código principal. Esto se traduce entre la intención del código principal y las funciones de bajo nivel requeridas para que las cosas sucedan, y
  • Bajo nivel (controlador), que en realidad voltea los bits correctos.

En este caso, las funciones de bajo nivel solo son vistas por el bloque de nivel medio. El bloque de nivel medio está expuesto al código principal.

Esto puede parecer demasiado complejo, pero en realidad no requiere mucho más trabajo. El beneficio ocurre si tiene que cambiar detalles de implementación más importantes.

Por ejemplo, digamos que ha diseñado su programa para usar un periférico SPI, pero su nuevo diseño realmente necesita usar I2C. Ahora puede cambiar el bloque de código de nivel medio para llamar correctamente a los comandos I2C de bajo nivel en lugar de los comandos SPI de bajo nivel. No tendría que cambiar ni el código de alto nivel ni el de bajo nivel.

Dicho esto, no recomendaría esto mientras todavía estás aprendiendo lo básico :)

Respuesta corta, no, no se garantiza que el código C escrito para un microcontrolador se ejecute en otros microcontroladores.

Respuesta larga, su compilador puede ocuparse de estos asuntos en gran medida, y también se pueden escribir bibliotecas que se ocupan de muchos detalles ocultos.

Por ejemplo, tiendo a usar el compilador PIC C de CCS para tratar con microcontroladores de la familia PIC. El código escrito para un microcontrolador simple generalmente se ejecutará en un controlador complejo, simplemente al incluir un archivo h diferente. Si trato de ejecutar un periférico que no existe, el compilador me dará un error (lo que impide que uno pase fácilmente de un controlador complejo a uno simple).

No hay nada mágico en esto. Alguien se tomó el tiempo de escribir definiciones para todas las ubicaciones de memoria relevantes, y escribió las funciones para llamar a estas definiciones y tomar las medidas apropiadas.

Para los controladores centrales STM32, existen bibliotecas CMSIS, lo que en teoría significa que si su fabricante de chips proporciona una biblioteca CMSIS, su código será MUY portátil para otros miembros de la familia central STM32, incluso aquellos de diferentes fabricantes.

¿Qué pasa si quiero usar el mismo código con otro AVR de 8 bits?

depende de la naturaleza del código.

el código dependiente del hardware obviamente no se ejecutará en una mcu con un hardware diferente. En la medida en que los dos mcus tengan el mismo hardware (TIMER0, por ejemplo), el código se ejecutará sin modificaciones.

El código independiente del hardware obviamente se ejecutará en cualquier mcu, en la medida en que los compiladores tengan el soporte.

El código podría funcionar, eso depende de su compilador y si los periféricos utilizados en su código, es decir, temporizadores y contadores, tienen los mismos registros.

El nombre de registro suele ser el mismo si trabaja con la misma familia de AVR. Algunos registros pueden aparecer, desaparecer si las características no son las mismas. Sin embargo, si opta por otro fabricante de uC, el nombre del registro será totalmente diferente. (Si pasa de microchip a TI, etc.)

Puede comenzar desde su código anterior porque la mayoría de los uC usan programación en C. La parte del algoritmo puede permanecer sin cambios. Deberá adaptar el registro para que el uC se comporte según lo previsto.