Programación de microcontroladores en C desde cero. CódigoVisionAVR. Información general para principiantes en programación en lenguaje C. ¿Qué microcontrolador elegir para trabajar?

De alguna manera, inmediatamente me sentí obligado a dar consejos sobre cómo elegir un entorno de programación para controladores AVR. Simplemente no me arrojes pantuflas. Estoy solo un poquito :)

Existen muchos lenguajes de programación para microcontroladores. También existen bastantes entornos de programación y es incorrecto compararlos entre sí. Mejores idiomas La programación no existe. Esto significa que tendrás que elegir el lenguaje y el entorno de programación más adecuados para ti.

Si actualmente se enfrenta a la elección de en qué empezar a trabajar, aquí tiene algunas recomendaciones.

Experiencia previa en programación. No descuides tu experiencia previa en programación. Incluso si fuera BÁSICO. Incluso si fue hace mucho tiempo en la escuela. Programar es como andar en bicicleta: una vez que comienzas, recuerdas rápidamente todo lo que has olvidado. Comience con BÁSICO, domínelo; luego será más fácil elegir algo más adecuado para sus propósitos.

Ayuda del medio ambiente.¿Tus amigos escriben en Pascal? El problema está resuelto: ¡escriba en Pascal! Siempre te ayudarán con consejos, te darán bibliotecas y te darán proyectos ya preparados para estudiar. En general, estarán encantados de darle la bienvenida a su comunidad. Si haces lo contrario, obtendrás el resultado contrario. Los amigos de la industria de la CEI te picotearán si decides estudiar ensamblador. No esperes ayuda.

Buen libro sobre programación AVR ayudará mucho. Desafortunadamente hay muy pocos de ellos. Si te topas con un libro y crees que está todo explicado de una manera muy accesible, pruébalo. No recomiendo estudiar con libros electrónicos, como último recurso, imprimirlos. Es muy inconveniente cambiar entre el entorno y el texto del archivo del libro. Es mucho más agradable leer un libro y probarlo enseguida, sin distraerse cambiando, además, puedes tomar notas en los márgenes y anotar las ideas que van surgiendo.

El entorno de programación es más sencillo. Si existen varios entornos de programación para tu lenguaje entre los que elegir, no lo dudes, elige el que te resulte más sencillo. Que sea menos funcional. Déjela compilar un código terriblemente inflado. Lo principal es empezar a trabajar. Una vez que se sienta cómodo en un entorno simple, podrá pasar fácilmente a un entorno más avanzado y "correcto". Y no escuches a quienes dicen que perderás más tiempo: se equivocan. A los alumnos de primaria no se les pide que lean "Guerra y paz", sino que se les entregan libros más sencillos, con dibujos.

Bibliotecas. La disponibilidad de bibliotecas es controvertida para el aprendizaje de idiomas. Por supuesto, más adelante harán la vida mucho más fácil, pero al principio las bibliotecas "Black Box" son incomprensibles y no contribuyen realmente a la comprensión del idioma. Por otro lado, hacen que los programas sean más fáciles de leer y permiten a un principiante crear programas complejos sin mucho esfuerzo. Así que no te preocupes demasiado por su presencia. Al menos al principio.

Código eficiente. Elegir un entorno de programación para aprender a programar basándose únicamente en la eficiencia del código que compila es una mala idea. Lo principal es que te sientas cómodo cuando empieces a estudiar; lo que salga de ello es lo décimo. Por supuesto, puedes trabajar en esto más tarde.

Magos. Cualquier dispositivo a bordo del chip debe configurarse mediante puertos. El procedimiento es bastante tedioso y se requieren hojas de datos. Además, hay matices que no son fáciles de captar para un principiante. Por tanto, es muy recomendable tener magos en el entorno. Los Vyzards son sintonizadores automáticos para SPI, I2C, USART, etc. Cuantos más dispositivos admitan, mejor. Usted configura los parámetros periféricos necesarios y el propio asistente genera un código que proporcionará los parámetros especificados. Hace la vida mucho más fácil.


Recomendaciones generales tal: la programación en la etapa inicial debe ser lo más simple posible (incluso primitiva). El entorno de programación debe ser fácil de aprender (ya que primero es necesario dominar la programación y no perder el tiempo jugueteando con la configuración). Preferiblemente rusificado. También serían útiles un manual en ruso y programas de muestra. Es deseable la capacidad de hacer brillar el cristal del entorno. Luego, a medida que domines los conceptos básicos de la programación, podrás pasar a shells más complejos.


Una última recomendación: trabajar con un cristal real. No tengas miedo de quemarlo. Adquirir experiencia práctica. Trabajar con emuladores (por ejemplo Proteus), aunque le liberará de tener que preocuparse por el soldador, nunca podrá darle la satisfacción que obtendrá con el programa de trabajo y el primer parpadeo del LED. ¡Entender que ha creado un diagrama de trabajo real con sus propias manos le da confianza y un incentivo para seguir adelante!

(Visitado 7,377 veces, 1 visitas hoy)

¡Hola querido Habrazhitel!

En este artículo quiero hablar de cómo una vez decidí empezar a programar microcontroladores, qué se necesitaba para ello y qué acabó pasando.

El tema de los microcontroladores me interesó hace mucho tiempo, allá por 2001. Pero luego resultó problemático conseguir un programador en mi lugar de residencia y no se trataba de comprarlo a través de Internet. Tuve que posponer este asunto hasta tiempos mejores. Y entonces, un buen día, descubrí que habían llegado tiempos mejores sin salir de casa, podía comprar todo lo que necesitaba. Me decidí a probarlo. Entonces lo que necesitamos:

1. programador
Hay muchas opciones en el mercado, desde los programadores ISP (Programación en el sistema) más baratos por unos pocos dólares hasta potentes programadores-depuradores por un par de cientos. Al no tener mucha experiencia en este asunto, primero decidí probar uno de los más simples y baratos: USBasp. Lo compré en eBay una vez por $12, ahora puedes encontrarlo incluso por $3-4. En realidad, se trata de una versión china del programador de Thomas Fischl. ¿Qué puedo decir de él? Sólo una cosa: funciona. Además, es compatible con muchos controladores AVR de las series ATmega y ATtiny. En Linux no se requiere ningún controlador.

Para actualizar el firmware es necesario conectar las salidas del programador VCC, GND, RESET, SCK, MOSI, MISO con las salidas correspondientes del microcontrolador. Para simplificar, monté el circuito auxiliar directamente en la placa:

A la izquierda del tablero está el mismo microcontrolador que vamos a flashear.

2. Microcontrolador
No me molesté demasiado en la elección del microcontrolador y tomé el ATmega8 de Atmel: 23 pines de E/S, dos temporizadores de 8 bits, uno de 16 bits, frecuencia de hasta 16 MHz, bajo consumo (1-3,6 mA) , barato ($2). En general, para empezar, más que suficiente.

En Linux, la combinación avr-gcc + avrdude funciona bien para compilar y cargar firmware en el controlador. La instalación es trivial. Siguiendo las instrucciones, podrás instalar todo el software necesario en unos minutos. El único matiz al que debes prestar atención es que avrdude (software para grabar en el controlador) puede requerir derechos de superusuario para acceder al programador. La solución es ejecutarlo mediante sudo (no es una muy buena idea) o registrar derechos especiales de udev. La sintaxis puede diferir en diferentes versiones del sistema operativo, pero en mi caso ( menta linux 15) agregar la siguiente regla al archivo /etc/udev/rules.d/41-atmega.rules funcionó:

# Programador USBasp SUBSYSTEM=="usb", ATTR(idVendor)=="16c0", ATTR(idProduct)=="05dc", GROUP="plugdev", MODE="0666"

Después de esto, por supuesto, debes reiniciar el servicio.
reinicio del servicio udev
Puedes compilar y flashear sin problemas directamente desde línea de comando(quién lo dudaría), pero si hay muchos proyectos, entonces es más conveniente instalar un complemento y hacer todo directamente desde el entorno Eclipse.

Para Windows tendrás que instalar un controlador. De lo contrario no hay problemas. Por motivos de interés científico, probé la combinación AVR Studio + eXtreme Burner en Windows. De nuevo, todo funciona muy bien.

Empecemos a programar

Los controladores AVR se pueden programar tanto en ensamblador (ensamblador AVR) como en C. Creo que aquí cada uno debería tomar su propia decisión en función de la tarea específica y de sus preferencias. Personalmente, comencé a jugar con el ensamblador. Al programar en ensamblador, la arquitectura del dispositivo se vuelve más clara y tienes la sensación de que estás profundizando directamente en el interior del controlador. Además, creo que en programas que son especialmente críticos en tamaño y rendimiento, los conocimientos de ensamblador pueden resultar muy útiles. Después de familiarizarme con el ensamblador AVR, me arrastré hasta C.

Después de familiarizarme con la arquitectura y los principios básicos, decidí crear algo útil e interesante. Aquí me ayudó mi hija, juega al ajedrez y una buena tarde me dijo que quería tener un cronómetro para las partidas cronometradas. ¡BAM! Aquí está: ¡la idea del primer proyecto! Por supuesto, puedes pedirlos en eBay, pero yo quería hacer mi propio reloj, con... eh... indicadores y botones negros. ¡Dicho y hecho!

Se decidió utilizar dos indicadores de diodos de 7 segmentos como pantalla. Para el control, bastaron 5 botones: "Reproductor 1", "Reproductor 2", "Restablecer", "Configuración" y "Pausa". Bueno, no te olvides de la indicación sonora del final del juego. Parece que eso es todo. La siguiente figura muestra un diagrama general de conexión del microcontrolador a indicadores y botones. Lo necesitaremos al analizar el código fuente del programa:

Interrogación

Comencemos, como era de esperar, desde el punto de entrada del programa: la función principal. De hecho, no tiene nada de extraordinario: configurar puertos, inicializar datos y un ciclo interminable de procesamiento de pulsaciones de botones. Bueno, llamar a sei() - habilitar el procesamiento de interrupciones, hablaremos de ello un poco más adelante.

Int main(void) ( init_io(); init_data(); sound_off(); sei(); while(1) ( handle_buttons(); ) devuelve 0; )
Veamos cada función por separado.

Void init_io() ( // establece la salida DDRB = 0xFF; DDRD = 0xFF; // establece la entrada DDRC = 0b11100000; // resistencias pull-up PORTC |= 0b00011111; // el temporizador interrumpe TIMSK = (1<

Configurar los puertos de E/S es muy sencillo: se escribe un número en el registro DDRx (donde x es la letra que designa el puerto), cada bit del cual significa si el pin correspondiente será un dispositivo de entrada (corresponde a 0) o un dispositivo de salida (corresponde a 1). Así, al enviar el número 0xFF a DDRB y DDRD, creamos puertos de salida B y D. En consecuencia, el comando DDRC = 0b11100000; convierte los primeros 5 pines del puerto C en pines de entrada y los restantes en pines de salida. Comando PORTC |= 0b00011111; Incluye resistencias pull-up internas en 5 entradas del controlador. Según el diagrama, a estas entradas se conectan botones que, cuando se presionan, los ponen en cortocircuito a tierra. De esta forma el controlador entiende que el botón está presionado.

Luego viene la configuración de dos temporizadores, Timer0 y Timer1. El primero lo utilizamos para actualizar los indicadores, y el segundo para la cuenta atrás del tiempo, habiéndolo configurado previamente para que se dispare cada segundo. Puede encontrar una descripción detallada de todas las constantes y el método para configurar el temporizador en un intervalo específico en la documentación de ATmega8.

Manejo de interrupciones

ISR (TIMER0_OVF_vect) ( display(); if (_buzzer > 0) ( _buzzer--; if (_buzzer == 0) sound_off(); ) ) ISR(TIMER1_COMPA_vect) ( if (ActiveTimer == 1 && Timer1 > 0) ( Temporizador1--; si (Temporizador1 == 0) tiempo_proceso(); ) si (TemporizadorActivo == 2 && Temporizador2 > 0) ( Temporizador2--; si (Temporizador2 == 0) tiempo_proceso(); ) )

Cuando se activa el temporizador, el control se transfiere al controlador de interrupciones apropiado. En nuestro caso, este es el controlador TIMER0_OVF_vect, que llama al procedimiento para mostrar el tiempo en los indicadores, y TIMER1_COMPA_vect, que procesa la cuenta regresiva.

Salida a indicadores

Pantalla vacía() ( display_number((Timer1/60)/10, 0b00001000); _delay_ms(0.25); display_number((Timer1/60)%10, 0b00000100); _delay_ms(0.25); display_number((Timer1%60)/10 , 0b00000010); _delay_ms(0.25); display_number((Timer1%60)%10, 0b00000001); _delay_ms(0.25); display_number((Timer2/60)/10, 0b10000000); _delay_ms(0.25); display_number((Timer2/ 60)%10, 0b01000000); _delay_ms(0.25); display_number((Timer2%60)/10, 0b00100000); _delay_ms(0.25); display_number((Timer2%60)%10, 0b00010000); _delay_ms(0.25); PORTD = 0; ) void display_number(int número, int máscara) ( PORTB = number_mask(número); PORTD = máscara; )

La función de visualización utiliza un método de visualización dinámica. El hecho es que cada indicador individual tiene 9 contactos (7 para control de segmento, 1 para punto y 1 para potencia). Para controlar 4 dígitos se necesitarían 36 contactos. Demasiado desperdicio. Por lo tanto, la salida de dígitos a un indicador con varios dígitos se organiza según el siguiente principio:

Se suministra voltaje alternativamente a cada uno de los contactos comunes, lo que le permite resaltar el número deseado en el indicador correspondiente utilizando los mismos 8 contactos de control. A una frecuencia de salida suficientemente alta, a la vista parece una imagen estática. Es por eso que los 8 contactos de alimentación de ambos indicadores en el diagrama están conectados a 8 salidas del puerto D, y 16 contactos de control de segmento están conectados en pares y conectados a 8 salidas del puerto B. Por lo tanto, la función de visualización con un retraso de 0,25 ms muestra alternativamente el número deseado en cada uno de los indicadores. Finalmente, se apagan todas las salidas que suministran voltaje a los indicadores (comando PORTD = 0;). Si no se hace esto, el último dígito mostrado seguirá iluminado hasta la siguiente llamada a la función de visualización, lo que hará que brille más en comparación con el resto.

Manejo de clics

void handle_buttons() ( handle_button(KEY_SETUP); handle_button(KEY_RESET); handle_button(KEY_PAUSE); handle_button(KEY_PLAYER1); handle_button(KEY_PLAYER2); ) void handle_button(int key) ( int bit; switch (key) ( case KEY_SETUP: bit = SETUP_BIT; romper; caso KEY_RESET: bit = RESET_BIT; romper; caso KEY_PAUSE: bit = PAUSE_BIT; romper; caso KEY_PLAYER1: bit = PLAYER1_BIT; romper; caso KEY_PLAYER2: bit = PLAYER2_BIT; romper; predeterminado: regresar; ) if (bit_is_clear( BUTTON_PIN, bit)) ( if (_pressed == 0) ( _delay_ms(DEBOUNCE_TIME); if (bit_is_clear(BUTTON_PIN, bit)) ( _pressed |= tecla; // interruptor de acción clave (tecla) ( case KEY_SETUP: Process_setup(); romper; caso KEY_RESET: proceso_reset(); romper; caso KEY_PAUSE: proceso_pausa(); romper; caso KEY_PLAYER1: proceso_player1(); romper; caso KEY_PLAYER2: proceso_player2(); romper; ) sound_on(15); ) ) ) else ( _pressed &= ~tecla; ) )

Esta función sondea los 5 botones por turno y procesa el clic, si corresponde. El clic se registra marcando bit_is_clear(BUTTON_PIN, bit) , es decir se pulsa el botón si la entrada correspondiente está conectada a tierra, lo que ocurrirá, según el esquema, al pulsar el botón. Se necesita un retraso de DEBOUNCE_TIME y comprobaciones repetidas para evitar múltiples operaciones innecesarias debido al rebote de contactos. Guardar el estado presionado en los bits correspondientes de la variable _pressed se utiliza para evitar disparos repetidos cuando el botón se presiona durante mucho tiempo.
Las funciones para procesar clics son bastante triviales y creo que no necesitan comentarios adicionales.

Texto completo del programa.

#definir F_CPU 4000000UL #incluir #incluir #incluir #definir DEBOUNCE_TIME 20 #definir BUTTON_PIN PINC #definir SETUP_BIT PC0 #definir RESET_BIT PC1 #definir PAUSE_BIT PC2 #definir PLAYER1_BIT PC3 #definir PLAYER2_BIT PC4 #definir KEY_SETUP 0b00000001 #definir KEY_RESET 0b00000010 # definir KEY_PAUSE 0b0000010 0 #definir KEY_PLAYER1 0b00001000 #definir KEY_PLAYER2 0b00010000 int volátil Temporizador activo = 0; volátil int Timer1 = 0; volátil int Timer2 = 0; volátil int _buzzer = 0; volátil int _pressed = 0; // declaraciones de funciones void init_io(); anular init_data(); int número_máscara(int número); void handle_buttons(); void handle_button (tecla int); vacío proceso_setup(); proceso nulo_reset(); vacío proceso_pausa(); vacío proceso_timeoff(); vacío proceso_jugador1(); vacío proceso_player2(); visualización nula(); void display_number(int máscara, int número); void sound_on(intervalo int); sonido vacío_off(); // interrumpe ISR (TIMER0_OVF_vect) ( display(); if (_buzzer > 0) ( _buzzer--; if (_buzzer == 0) sound_off(); ) ) ISR(TIMER1_COMPA_vect) ( if (ActiveTimer == 1 && Timer1 > 0) ( Temporizador1--; if (Temporizador1 == 0) Process_timeoff(); ) if (ActiveTimer == 2 && Timer2 > 0) ( Temporizador2--; if (Timer2 == 0) Process_timeoff(); ) ) int main (void) ( init_io(); init_data(); sound_off(); sei(); while(1) ( handle_buttons(); ) devuelve 0; ) void init_io() ( // establece la salida DDRB = 0xFF; DDRD = 0xFF ; // establece la entrada DDRC = 0b11100000; // resistencias pull-up PORTC |= 0b00011111; // el temporizador interrumpe TIMSK = (1<5940 || Temporizador2 > 5940) ( Temporizador1 = 0; Temporizador2 = 0; ) ) void Process_reset() ( init_data(); ) void Process_timeoff() ( init_data(); sound_on(30); ) void Process_pause() ( ActiveTimer = 0; ) void Process_player1() ( ActiveTimer = 2; ) void Process_player2() ( ActiveTimer = 1; ) void handle_button(int key) ( int bit; switch (key) ( case KEY_SETUP: bit = SETUP_BIT; break; case KEY_RESET: bit = RESET_BIT ; romper; caso KEY_PAUSE: bit = PAUSE_BIT; romper; caso KEY_PLAYER1: bit = PLAYER1_BIT; romper; caso KEY_PLAYER2: bit = PLAYER2_BIT; romper; predeterminado: regresar; ) if (bit_is_clear(BUTTON_PIN, bit)) ( if (_pressed == 0) ( _delay_ms(DEBOUNCE_TIME); if (bit_is_clear(BUTTON_PIN, bit)) ( _pressed |= tecla; // interruptor de acción clave (tecla) ( case KEY_SETUP: Process_setup(); break; case KEY_RESET: Process_reset(); break; caso KEY_PAUSE: proceso_pausa(); descanso; caso KEY_PLAYER1: proceso_jugador1(); descanso; caso KEY_PLAYER2: proceso_jugador2(); descanso; ) sonido_on(15); ) ) ) más ( _presionado &= ~tecla; ) ) void handle_buttons() ( handle_button(KEY_SETUP); handle_button(KEY_RESET); handle_button(KEY_PAUSE); handle_button(KEY_PLAYER1); handle_button(KEY_PLAYER2); ) void display() ( display_number((Timer1/60)/10, 0b00001000) ; _delay_ms(0.25); display_number((Timer1/60)%10, 0b00000100); _delay_ms(0.25); display_number((Timer1%60)/10, 0b00000010); _delay_ms(0.25); display_number((Timer1%60)% 10, 0b00000001); _delay_ms(0.25); display_number((Timer2/60)/10, 0b10000000); _delay_ms(0.25); display_number((Timer2/60)%10, 0b01000000); _delay_ms(0.25); display_number((Timer2) %60)/10, 0b00100000); _delay_ms(0.25); display_number((Timer2%60)%10, 0b00010000); _delay_ms(0.25); PORTD = 0; ) void display_number(int número, int máscara) ( PORTB = número_máscara (número); PORTD = máscara; ) void sound_on(int intervalo) ( _buzzer = intervalo; // poner el pin del timbre alto PORTC |= 0b00100000; ) void sound_off() ( // poner el pin del timbre bajo PORTC &= ~0b00100000; )

El prototipo se montó sobre una placa de pruebas.

Lección 0.

Entonces, hoy abrimos una serie de lecciones sobre programación de microcontroladores de la familia AVR.

Hoy se considerarán las siguientes preguntas:

  1. ¿Qué es un microcontrolador?
  2. ¿Dónde se utilizan los microcontroladores?

Introducción.

Los microcontroladores están en todas partes. En teléfonos, lavadoras, “hogares inteligentes”, máquinas herramienta en fábricas y también en muchos otros dispositivos técnicos. Su uso generalizado permite sustituir circuitos analógicos complejos por circuitos digitales más comprimidos.

Entonces, ¿qué es un microcontrolador?

Microcontrolador (Unidad de microcontrolador, MCU) - un microcircuito diseñado para controlar dispositivos electrónicos. Se puede imaginar como una simple computadora capaz de interactuar con dispositivos externos, por ejemplo, abrir y cerrar transistores, recibir datos de sensores de temperatura, mostrar datos en pantallas LCD, etc. Además, el microcontrolador puede realizar diversos procesamientos de datos de entrada, al igual que su computadora personal.

Es decir, los microcontroladores nos ofrecen posibilidades casi ilimitadas para controlar cualquier dispositivo, gracias a la presencia de puertos I/0 (puertos de entrada/salida), así como la posibilidad de programarlos.

¿Dónde se utilizan los microcontroladores?

  1. Electrodomésticos (Lavadoras, hornos microondas, etc.).
  2. Tecnología móvil (Robots, sistemas robóticos, equipos de comunicaciones, etc.).
  3. Equipos industriales (sistemas de control de máquinas).
  4. Tecnología informática (Placas base, sistemas de control de dispositivos periféricos).
  5. Equipos de entretenimiento (Juguetes infantiles, adornos).
  6. Transporte (Sistemas de control de motores de automóviles, sistemas de seguridad)

Esta no es una lista completa de aplicaciones para microcontroladores. A menudo, resulta muy rentable sustituir un conjunto de chips de control por un microcontrolador, debido a la simplificación de la producción y al reducido consumo de energía.

Empezando con AVR

AVR- una familia de microcontroladores de Atmel que tienen un rendimiento suficiente para la mayoría de los dispositivos de aficionados. También son muy utilizados en la industria.

Existen varios lenguajes de programación para microcontroladores AVR, pero quizás los más adecuados sean ensamblador y C, ya que estos lenguajes implementan mejor todas las capacidades necesarias para administrar el hardware del microcontrolador.

El lenguaje ensamblador es un lenguaje de programación de bajo nivel que utiliza el conjunto de instrucciones directas del microcontrolador. Crear un programa en este lenguaje requiere un buen conocimiento del sistema de comando del chip programable y tiempo suficiente para desarrollar el programa. El lenguaje ensamblador es inferior a C en velocidad y facilidad de desarrollo de programas, pero tiene ventajas notables en el tamaño del código ejecutable final y, en consecuencia, en la velocidad de su ejecución.

C permite crear programas con mucha mayor comodidad, brindando al desarrollador todos los beneficios de un lenguaje de alto nivel.
Cabe señalar una vez más que la arquitectura y el sistema de comando de AVR se crearon con la participación directa de los desarrolladores del compilador del lenguaje C y tienen en cuenta las características de este lenguaje. La compilación del código fuente C es rápida y produce un código compacto y eficiente.

Las principales ventajas de C sobre el ensamblador: alta velocidad de desarrollo de programas; universalidad que no requiere un estudio exhaustivo de la arquitectura del microcontrolador; mejor documentabilidad y legibilidad del algoritmo; disponibilidad de bibliotecas de funciones; soporte para cálculos de punto flotante.

El lenguaje C combina armoniosamente capacidades de programación de bajo nivel con las propiedades de un lenguaje de alto nivel. La capacidad de programación de bajo nivel le permite operar fácilmente directamente en el hardware, y las propiedades del lenguaje de alto nivel le permiten crear código de programa fácilmente legible y modificable. Además, casi todos los compiladores de C tienen la capacidad de utilizar inserciones de ensamblador para escribir secciones de programa que son críticas en términos de tiempo de ejecución y consumo de recursos.

En una palabra, C es el lenguaje más conveniente tanto para los principiantes que se familiarizan con los microcontroladores AVR como para los desarrolladores serios.

Los compiladores se utilizan para convertir el código fuente de un programa en un archivo de firmware de microcontrolador.

Atmel proporciona un potente compilador ensamblador que se incluye en el entorno de desarrollo Atmel Studio que se ejecuta en Windows. Además del compilador, el entorno de desarrollo contiene un depurador y un emulador.
Atmel Studio es completamente gratuito y está disponible en el sitio web de Atmel.

Actualmente, existen bastantes compiladores de C para AVR. Se considera que el más potente de ellos es el compilador de IAR Systems de Estocolmo. Fueron sus empleados quienes participaron en el desarrollo del sistema de comando AVR a mediados de los años 90. IAR C Compiler tiene amplias capacidades de optimización de código y forma parte del entorno de desarrollo integrado IAR Embedded Workbench (EWB), que también incluye un compilador ensamblador, un enlazador, un administrador de bibliotecas y proyectos, y un depurador. El precio de la versión completa del paquete es de 2820 EUR. En el sitio web de la empresa puedes descargar una versión de evaluación gratuita durante 30 días o una versión ilimitada con un límite de tamaño de código de 4 KB.

La empresa estadounidense Image Craft de Palo Alto, California, produce un compilador en lenguaje C que ha ganado bastante popularidad. JumpStart C para AVR tiene una optimización de código aceptable y un precio no demasiado elevado (de 50 dólares a 499 dólares según la versión). La versión de demostración de JumpStart C para AVR es completamente funcional durante 45 días.

El compilador rumano Code Vision AVR C no ha ganado menos popularidad; el precio de la versión completa de este compilador es relativamente bajo y asciende a 150 EUR. El compilador viene con un entorno de desarrollo integrado que, además de las funciones estándar, incluye una característica bastante interesante: el generador automático de programas CodeWizardAVR. La presencia de un terminal serie en el entorno de desarrollo le permite depurar programas utilizando el puerto serie del microcontrolador. Puede descargar una versión de evaluación gratuita de los desarrolladores con un límite de tamaño de código de 4 KB y deshabilitado el guardado del código fuente generado en C.

La empresa MikroElektronika, ubicada en la ciudad serbia de Belgrado, produce toda una familia de compiladores para microcontroladores AVR. Un compilador para el lenguaje C llamado mikroC PRO para AVR cuesta 249 dólares. También hay mikroBasic y mikroPascal por el mismo precio. Hay versiones de demostración en el sitio web de los desarrolladores con un límite de tamaño de código de 4096 bytes. La ventaja de esta familia de compiladores es una única plataforma y una única ideología, que puede proporcionar una transición sencilla no sólo entre lenguajes, sino también entre microcontroladores (existen versiones de compiladores para PIC, STM32, 8051...).

El entorno de desarrollo integrado se ha vuelto verdaderamente icónico. Incluye potentes compiladores C y ensamblador, el programador AVRDUDE, un depurador, un simulador y muchos otros programas y utilidades de soporte. WinAVR se integra perfectamente con el entorno de desarrollo AVR Studio de Atmel. El ensamblador es idéntico en código de entrada al ensamblador de AVR Studio. Los compiladores C y ensamblador tienen la capacidad de crear archivos de depuración en formato COFF, lo que le permite utilizar no solo las herramientas integradas, sino también el potente simulador AVR Studio. Otra ventaja importante es que WinAVR se distribuye de forma gratuita y sin restricciones (los fabricantes admiten la licencia pública general GNU).

A modo de resumen, cabe decir que WinAVR es una opción ideal para quienes están empezando a dominar los microcontroladores AVR. Es este entorno de desarrollo el que se considera principal en este curso.

Kiselev Roman, mayo de 2007 Artículo actualizado el 26 de mayo de 2014.

Entonces, ¿qué es un microcontrolador (en adelante MK)? Se trata, relativamente hablando, de un pequeño ordenador alojado en un único circuito integrado. Tiene un procesador (unidad aritmética lógica o ALU), memoria flash, memoria EEPROM, muchos registros, puertos de E/S, así como elementos adicionales como temporizadores, contadores, comparadores, USART, etc. Después de aplicar energía , el microcontrolador se inicia y comienza a ejecutar el programa almacenado en su memoria flash. Al mismo tiempo, puede controlar una amplia variedad de dispositivos externos a través de puertos de E/S.

¿Qué quiere decir esto? Esto significa que en el MK puedes implementar cualquier circuito lógico que realice determinadas funciones. Esto significa que MK es un microcircuito cuyo contenido interno, de hecho, lo creamos nosotros mismos. Esto permite, después de haber comprado varios MK completamente idénticos, ensamblar en ellos circuitos y dispositivos completamente diferentes. Si deseas realizar algún cambio en el funcionamiento de un dispositivo electrónico, no necesitarás utilizar un soldador, solo necesitarás reprogramar el MK. En este caso, ni siquiera necesita quitarlo de su dispositivo si está utilizando un AVR, ya que estos MK admiten programación en circuito. Así, los microcontroladores cierran la brecha entre la programación y la electrónica.

Los AVR son microcontroladores de 8 bits, es decir, su ALU puede realizar operaciones sencillas con sólo números de 8 bits en un ciclo de reloj. Ahora es el momento de hablar sobre qué MK usaremos. Estoy trabajando con un ATMega16 MK. Es muy común y se puede comprar en casi cualquier tienda de repuestos para radio por unos 100 rublos. Si no lo encuentras, puedes comprar cualquier otro MK de la serie MEGA, pero en este caso tendrás que buscar documentación, ya que las mismas “patas” de diferentes MK pueden realizar diferentes funciones, y por conectando, al parecer, si todas las conclusiones son correctas, es posible que obtenga un dispositivo que funcione, o tal vez solo una nube de humo apestoso. Al comprar un ATMega16, asegúrese de que venga en un paquete DIP grande de 40 pines y también compre un enchufe en el que se pueda insertar. Para trabajar con él, también necesitarás dispositivos adicionales: LED, botones, conectores, etc.

ATMega16 tiene una gran cantidad de funciones diversas. Estas son algunas de sus características:

  • Frecuencia máxima de reloj: 16 MHz (8 MHz para ATMega16L)
  • La mayoría de los comandos se ejecutan en un ciclo de reloj.
  • 32 registros de trabajo de 8 bits
  • 4 puertos de E/S completos de 8 bits
  • dos temporizadores/contadores de 8 bits y uno de 16 bits
  • Convertidor analógico a digital (ADC) de 10 bits
  • generador de reloj interno a 1 MHz
  • comparador analógico
  • interfaces SPI, I2C, TWI, RS-232, JTAG
  • programación en circuito y autoprogramación
  • Módulo de modulación de ancho de pulso (PWM)

Las características completas de este dispositivo, así como las instrucciones para su uso, se pueden encontrar en el libro de referencia (Hoja de datos) de este MK. Es cierto que está en inglés. Si sabe inglés, asegúrese de descargar esta hoja de datos, contiene mucha información útil.

Finalmente pongámonos manos a la obra. Recomiendo hacer una placa especial de desarrollo y depuración para el microcontrolador, en la que se pueda montar cualquier circuito eléctrico con un microcontrolador sin soldador (o casi sin él). El uso de una placa de este tipo facilitará enormemente el trabajo con el MK y acelerará el proceso de aprendizaje de su programación. Se parece a esto:

¿Qué necesitarás para esto?

Primero, necesitarás el tablero. Compré uno ya hecho en una tienda de repuestos para radio por 115 rublos. Luego le soldé todas las piezas necesarias. El resultado es algo increíblemente conveniente en el que puede ensamblar cualquier circuito eléctrico en cuestión de minutos conectando cables e instalando microcircuitos e indicadores.

Para conectar elementos del circuito es muy conveniente utilizar cables con conectores en los extremos. Estos conectores se colocan en las “patas” que sobresalen al lado de cada puerto del MK. El microcontrolador debe instalarse en el zócalo y no soldarse a la placa; de lo contrario, será muy difícil quitarlo si lo quema accidentalmente. A continuación se muestra la distribución de pines del ATMEGA16 MK:

Expliquemos qué patas nos interesan ahora.

  • VCC: aquí se suministra energía (4,5 - 5,5 V) desde una fuente estabilizada
  • GND – tierra
  • RESET – reinicio (a bajo nivel de voltaje)
  • XTAL1, XTAL2: aquí se conecta un resonador de cuarzo
  • PA, PB, PC, PD – puertos de entrada/salida (A, B, C y D, respectivamente).

Cualquier cosa que produzca 7-11 V CC se puede utilizar como fuente de energía. Para un funcionamiento estable del MK, se necesita una fuente de alimentación estabilizada. Como estabilizador, se pueden utilizar microcircuitos de la serie 7805. Estos son estabilizadores lineales integrados, cuya entrada se alimenta con 7-11 V de corriente continua no estabilizada y la salida es de 5 V de corriente estabilizada. Antes y después del 7805, es necesario instalar condensadores de filtro (electrolíticos para filtrar interferencias de baja frecuencia y cerámicos para las de alta frecuencia). Si no puede encontrar un estabilizador, puede utilizar como fuente de alimentación una batería de 4,5 V. El MK debe alimentarse directamente desde ella.

A continuación se muestra un diagrama de la conexión MK:

Ahora averigüemos qué es qué aquí.

BQ1 es un resonador de cuarzo que establece la frecuencia de funcionamiento del MK. Puede configurar cualquiera hasta 16 MHz, pero como planeamos trabajar con un puerto COM en el futuro, recomiendo usar resonadores para las siguientes frecuencias: 14,7456 MHz, 11,0592 MHz, 7,3725 MHz, 3,6864 MHz o 1,8432 MHz (más tarde quedará claro por qué). Usé 11.0592 MHz. Está claro que cuanto mayor sea la frecuencia, mayor será la velocidad del dispositivo.

R1 es una resistencia pull-up que mantiene un voltaje de 5 V en la entrada RESET. Un nivel de voltaje bajo en esta entrada indica un reinicio. Después del reinicio, el MK arranca (10 - 15 ms) y comienza a ejecutar el programa nuevamente. Dado que se trata de una entrada de alta impedancia, no puede dejarla "colgando en el aire": una pequeña captación provocará un reinicio inesperado del MK. Esto es exactamente para lo que sirve R1. Para mayor confiabilidad, también recomiendo instalar el capacitor C6 (no más de 20 µF).

SB1 – botón de reinicio.

El resonador de cuarzo y el condensador de filtro C3 deben ubicarse lo más cerca posible del MK (no más de 5-7 cm), ya que de lo contrario pueden producirse interferencias en los cables, lo que provocará un mal funcionamiento del MK.

El rectángulo azul en el diagrama describe el propio programador. Es conveniente hacerlo en forma de cable, un extremo del cual está enchufado al puerto LPT y el otro a un conector determinado al lado del MK. El cable no debe ser excesivamente largo. Si surgen problemas con este cable (normalmente no es así, pero puede pasar cualquier cosa), tendrás que soldar el adaptador Altera ByteBlaster. Cómo hacer esto está escrito en la descripción del programador AVReal.

Ahora que nos hemos ocupado del hardware, es hora de pasar al software.

Existen varios entornos de desarrollo para la programación de AVR. En primer lugar, este es AVR Studio, el sistema de programación oficial de Atmel. Le permite escribir en ensamblador y depurar programas escritos en ensamblador, C y C++. IAR es un sistema de programación comercial en C, C++ y lenguaje ensamblador. WinAVR es un compilador de código abierto. AtmanAVR es un sistema de programación para AVR con una interfaz casi exactamente igual a Visual C++ 6. AtmanAVR también le permite depurar programas y contiene muchas funciones auxiliares que facilitan la escritura de código. Este sistema de programación es comercial, pero, según la licencia, puedes usarlo gratis durante un mes.

Sugiero comenzar a trabajar con IAR como el entorno de desarrollo más transparente. En IAR, un proyecto se crea completamente a mano, por lo tanto, después de haber completado varios proyectos, ya sabrá claramente qué significa cada línea de código y qué sucederá si la cambia. Cuando trabaje con AtmanAVR, tendrá que utilizar una plantilla creada previamente, que es muy engorrosa y difícil de entender para una persona sin experiencia, o tendrá muchos problemas con los archivos de encabezado al ensamblar el proyecto desde cero. Después de habernos ocupado del IAR, veremos a continuación otros compiladores.

Entonces, primero, consiga algo de IAR. Es muy común y encontrarlo no debería ser un problema. Después de descargar IAR 3.20 desde algún lugar, instale el compilador/entorno de trabajo y ejecútelo. Después de esto puedes empezar a trabajar.

Habiendo iniciado IAR, seleccione archivo/nuevo/espacio de trabajo, seleccione la ruta a nuestro proyecto y cree una carpeta para él y asígnele un nombre, por ejemplo, "Prog1". Ahora creemos un proyecto: Proyecto / Crear nuevo proyecto… Llamémoslo también “Prog1”. Haga clic derecho en el título del proyecto en el árbol del proyecto y seleccione "Opciones"

Aquí configuraremos el compilador para un MK específico. Primero, debe seleccionar el tipo de procesador ATMega16 en la pestaña Destino, marcar la casilla Habilitar definiciones de bits en archivos de inclusión de E/S en la pestaña Configuración de biblioteca (para que pueda usar los nombres de bits de varios registros MK en el código del programa ) y seleccione allí el tipo de biblioteca C /EU++. En la categoría ICCAVR, debe marcar la casilla Habilitar soporte multibyte en la pestaña Idioma y desactivar la optimización en la pestaña Optimización (de lo contrario, arruinará nuestro primer programa).

A continuación, seleccione la categoría XLINK. Aquí debe determinar el formato del archivo compilado. Dado que ahora estamos configurando opciones para el modo de depuración, como se describe en el título, necesitamos obtener un archivo de depuración como salida. Posteriormente lo abriremos en AVR Studio. Para hacer esto, debe seleccionar la extensión.cof y el tipo de archivo es ubrof 7.

Ahora haga clic en Aceptar, luego cambie Depurar a Liberar.

Vaya a Opciones nuevamente, donde todos los parámetros excepto XLINK están configurados de la misma manera. En XLINK, cambie la extensión a .hex y el formato del archivo a intel-standart.

Eso es todo. Ahora puedes empezar a escribir tu primer programa. Cree una nueva fuente/texto e ingrese el siguiente código en él:

#incluir"iom16.h" corto sin firmar int i; vacío principal( vacío) (DDRB = 255; PUERTOB = 0; mientras(1) { si(PUERTOB == 255) PUERTOB = 0; demás PUERTOB++; para(yo=0; yo

El archivo "iom16.h" se encuentra en la carpeta (C:\Archivos de programa)\IAR Systems\Embedded Workbench 3.2\avr\inc. Si está utilizando otro MK, por ejemplo, ATMega64, seleccione el archivo "iom64.h". Estos archivos de encabezado almacenan información sobre el MK: los nombres de los registros, los bits de los registros y los nombres de las interrupciones. Cada pin individual del puerto A, B, C o D puede actuar como entrada o salida. Esto está determinado por el Registro de dirección de datos (DDR). 1 convierte el tramo en una salida, 0 en una entrada. Así, al establecer, por ejemplo, DDRA = 13, hacemos las "patas" PB0, PB2, PB3 salidas, el resto - entradas, porque 13 en binario es 00001101.

PORTB es un registro que determina el estado de los pines del puerto. Después de escribir 0 allí, establecemos el voltaje en todas las salidas en 0 V. Luego aparece un bucle sin fin. Al programar el MK siempre hacen un bucle sin fin en el que el MK realiza alguna acción hasta que se resetea o hasta que se produce una interrupción. En este ciclo escriben, por así decirlo, "código de fondo", que el MK ejecuta como último paso. Esto podría ser, por ejemplo, mostrar información en una pantalla. En nuestro caso, el contenido del registro PORTB se incrementa hasta llenarlo. Después de eso todo empieza de nuevo. Finalmente, un bucle for de diez mil ciclos. Es necesario para formar un retraso visible al cambiar el estado del puerto B.



Ahora guardamos este archivo en la carpeta del proyecto como Prog1.c, copiamos el archivo iom16.h a la carpeta del proyecto, seleccionamos Proyecto/Agregar archivos y agregamos “iom16.h” y “Prog1.c”. Seleccione Liberar, presione F7, el programa se compila y debería aparecer el mensaje:


Número total de errores: 0
Número total de advertencias: 0

Aquí hay una foto de mi programador:

Descarga el programador AVReal. Cópielo (AVReal32.exe) a la carpeta Release/exe, donde debería ubicarse el archivo Prog1.hex. Suministramos energía al MK, conectamos el cable de programación. Abra Far Manager (lo más conveniente es flashear MK), vaya a esta carpeta y presione Ctrl+O. Como tenemos un MK completamente nuevo, rellenamos

avreal32.exe +MEGA16 -o11.0592MHZ -p1 -fblev=0,jtagen=1,cksel=F,sut=1 –w

¡No olvides ingresar la frecuencia correcta si no estás usando 11059200 Hz! Al mismo tiempo, el llamado fusibles – registros que controlan su funcionamiento (uso de un generador interno, Jtag, etc.). Después de esto, estará listo para recibir el primer programa. El programador recibe como parámetros el puerto LPT utilizado, la frecuencia, el nombre del archivo y otros (todos ellos se enumeran en la descripción de AVReal). Marcamos:

Avreal32.exe +Mega16 -o11.0592MHz -p1 -e -w -az -% Prog1.hex

Si la conexión es correcta, el programador informará de una programación exitosa. No hay garantía de que esto funcione la primera vez (la primera vez que llama al programa). A veces yo mismo me programo por segunda vez. Quizás el puerto LPT esté defectuoso o haya interferencias en el cable. Si ocurren problemas, revise su cable cuidadosamente. Por mi propia experiencia sé que el 60% de las averías están asociadas a la falta de contacto en el lugar correcto, el 20% a la presencia de uno innecesario y el otro 15% a una soldadura errónea de lo incorrecto a lo incorrecto. Si todo lo demás falla, lea la descripción del programador e intente construir Byte Blaster.

Supongamos que todo funciona para usted. Si ahora conecta ocho LED al puerto B del MK (haga esto con el MK apagado, y es recomendable incluir resistencias de 300-400 ohmios en serie con los LED) y aplica energía, ocurrirá un pequeño milagro: un " ¡Ola” los atravesará!

© Kiselev Roman
mayo de 2007


Arriba