8 votos

Inesperado Atmega16 respuesta en la UART

Inesperado Atmega16 respuesta en la UART

Breve resumen del problema

He flasheado un Atmega16 con el código que debe resultar en el Atmega16 envío de cualquier carácter que envío a través de un terminal. Puedo obtener una respuesta, pero es rara vez el personaje que me envió. Puedo ver la salida correcta, cambiando la velocidad en baudios, pero no entiendo por qué la velocidad en baudios correcta de las obras.

Más detalles

Estoy tratando de aprender más sobre el firmware de programación en mi propio tiempo porque estoy bastante de disfrutar de ella. Hasta el momento en el firmware de programación que he hecho en la uni, nos han dado el esqueleto de los archivos de código que hacen muchos de los periféricos de interfaz y configurar para nosotros, pero me gustaría aprender esto a mí mismo. Tengo un par de preguntas acerca de lo que estoy haciendo aquí salpicadas a lo largo de los post, pero voy a detallar todos ellos en la final. Si usted recoger en cualquier malentendido o las posibles lagunas en mi conocimiento, yo le agradecería cualquier opinión que pueda tener.

El código

El código que he flasheado en mi Atmega16, está tomado casi línea por línea de la 'Usando la USART en AVR-GCC' tutorial encontrado en esta página. Todos los que he añadido es el #define para F_CPU. El código original no tiene un #define para F_CPU así que mi código no compila en AtmelStudio 7. Podría alguien explicar por qué el autor no ha definido F_CPU en su archivo original? Supongo que puede haber sido el uso de otra herramienta o compilador de Atmel Studio 7 pero no puedo decir con certeza.

#include <avr/io.h>
#define F_CPU 7372800 //this was chosen because the tutorial states this is the frequency we want to operate at
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((( F_CPU / 16) + ( USART_BAUDRATE / 2)) / ( USART_BAUDRATE )) - 1)

int main ( void )
{
    char ReceivedByte ;
    UCSRB = (1 << RXEN ) | (1 << TXEN ); // Turn on the transmission and reception circuitry
    UCSRC = (1 << URSEL ) | (1 << UCSZ0 ) | (1 << UCSZ1 ); // Use 8- bit character sizes
    UBRRH = ( BAUD_PRESCALE >> 8); // Load upper 8- bits of the baud rate value into the high byte of the UBRR register
    UBRRL = BAUD_PRESCALE ; // Load lower 8- bits of the baud rate value into the low byte of theUBRR register
    for (;;) // Loop forever
    {
        while (( UCSRA & (1 << RXC )) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
        ReceivedByte = UDR ; // Fetch the received byte value into the variable " ByteReceived "
        while (( UCSRA & (1 << UDRE )) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
        UDR = ReceivedByte ; // Echo back the received byte back to the computer
    }
}

El programa de instalación de hardware

Photo of the hardware setup

  • MCU: Atmega16;
  • Herramientas: Atmel Studio 7, parpadeando con AVR dragon;
  • Fuente de alimentación: 5V ferrocarril tomado de una universidad de la junta de desarrollo (que se toma de USB de la computadora). 100nF de disco de cerámica del condensador utilizado para pasar por encima de la placa de alimentación de las líneas de
  • Conversor USB a serie: Este uno. TXD en el conversor USB a serie conectado a RXD Atmega (Pin 15). RXD en el convertidor conectado a RXD en Atmega (Pin 14).
  • El software de Terminal: Masilla (con la velocidad en baudios de 9600).

    La evidencia de las respuestas incorrectas

    Para reiterar, el Atmega debe devolver lo que se le ha enviado es decir, la SALIDA debe ser exactamente la misma ENTRADA.

    La masilla de salida

    \begin{array} \hline \text{INPUT} & \text{OUTPUT} \\ \hline \text{f} & \text{&}\\ \hline \text{f} & \text{6}\\ \hline \text{z} & \text{>}\\ \hline \text{d} & \text{0}\\ \hline \text{space} & \text{0}\\ \hline \text{x} & \text{8}\\ \hline \end{array}

    Osciloscopio De Captura

    He utilizado mi Picoscope con la decodificación en serie para comprobar que el Atmega está recibiendo la entrada correcta, que parece ser. Por ejemplo, cuando me de prensa de la 'f', es recibido correctamente. La salida es todavía un '6' (o un signo '&' en la ocasión).

Scope capture on the RX pin of the Atmega16 showing that the correct character is being sent via the terminal software ('f')

Scope capture on the TX pin of the Atmega16 showing that an undesired response is being sent back ('6')

Una solución que me topé con que no entiendo

Si puedo cambiar la velocidad en baudios a 2500in Masilla, todo se muestra correctamente. Elegí este valor de forma aleatoria y no sé por qué funciona (esto me lleva a creer que ha cometido un error en alguna parte que ver con la velocidad pero no la puedo ver si he copiado el tutorial casi exactamente... yo pensaba).

Preguntas

  1. Lo que he hecho mal/¿qué está pasando aquí?
  2. ¿Por qué el tutorial original no #define F_CPU?
  3. ¿Por qué la configuración de la velocidad en baudios a 2500 solucionar el problema? (Sospecho que esto va a ser contestado si a la pregunta 1 es contestada)

0voto

Martin Puntos 267

He descubierto! Gracias a los comentarios acerca de F_CPU en respuesta a la OP hice algo de investigación (esto puede ser obvio para todos ustedes).

Breve resumen de la solución

El Atmega16 no estaba funcionando en la frecuencia, pensé que era porque yo no entiendo cómo cambiar la frecuencia del sistema. Mediante la comprobación de los fusibles en Atmel Studio yo podía ver que se estaba ejecutando en 2MHz (este no es el estándar de la frecuencia de reloj como lo que yo sé, pero no voy a entrar en eso), y no 7.3728 MHz como el tutorial.

F_CPU ¿ no cambiar la frecuencia de reloj de la MCU (el Atmega16). La frecuencia de la Atmega16 fue no cambiar a 7.3728 MHz como era necesario para obtener el código de ejemplo para el trabajo. Todavía estaba funcionando a la frecuencia definida por los fusibles (2 mhz en este caso, más sobre esto más adelante) por lo que el papel de cálculo de la deseada velocidad en baudios difiere de lo que realmente se utiliza.

Código de trabajo

#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 2000000 //THIS LINE IS **NOT** CHANGING THE FREQUENCY OF THE MCU: CHANGE MCU FREQUENCY IN FUSES
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((( F_CPU / 16) + ( USART_BAUDRATE / 2)) / ( USART_BAUDRATE )) - 1)

int main ( void ){
    char ReceivedByte ;
    UCSRB = (1 << RXEN ) | (1 << TXEN ); // Turn on the transmission and reception circuitry
    UCSRC = (1 << URSEL ) | (1 << UCSZ0 ) | (1 << UCSZ1 ); // Use 8- bit character sizes
    UBRRH = ( BAUD_PRESCALE >> 8); // Load upper 8- bits of the baud rate value into the high byte of the UBRR register
    UBRRL = BAUD_PRESCALE ; // Load lower 8- bits of the baud rate value into the low byte of theUBRR register
    for (;;){ // Loop forever
        while (( UCSRA & (1 << RXC )) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
        ReceivedByte = UDR ; // Fetch the received byte value into the variable " ByteReceived "
        while (( UCSRA & (1 << UDRE )) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
        UDR = ReceivedByte ; // Echo back the received byte back to the computer
    }
}

Más detalles

La velocidad en baudios deseada vs lo que el Atmega estaba realmente haciendo

La velocidad en baudios deseada (desde el tutorial) fue 9600, que es la velocidad en baudios que he usado en la Masilla. El real de la velocidad en baudios puede ser calculada usando la ecuación en la Tabla 60 (página 147) de la Atmega16 hoja de datos.

Table of equations to calculate baudrate and UBRR from page 147 Atmega16 datasheet

En el código de ejemplo BAUD_PRESCALE es UBRR en el cálculo. BAUD_PRESCALE es evaluado como 47 con los valores definidos para F_CPU y USART_BAUDRATE.

$$\text{BAUD} = \frac{f_{osc}}{16(\text{UBRR} + 1)} $$ $$\text{BAUD} = \frac{2,000,000}{16(\text{47} + 1)} $$ $$\text{BAUD} \approx 2,604 $$

Y esta fue la raíz de la cuestión. El Atmega16 estaba en funcionamiento en 2 mhz, lo que significa que el valor de f_{osc} fue diferente para el ejemplo de este tutorial, lo que resultó en una tasa de baudios de 2,604 frente a 9,600.

Observe que f_osc es el real de la frecuencia del sistema de la MCU, que es no determinado por F_CPU.

De modo que también responde a mi 3ª pregunta: el cambio de la velocidad en baudios a 2,500 por suerte lo suficientemente cerca como para el operativo de la velocidad en baudios del MCU que el terminal podría interpretar correctamente los resultados.

El cambio de la frecuencia de la MCU

Para cambiar la frecuencia de la MCU en AtmelStudio 7, ir a:

Tools > Device programming > Fuses > Change SUT_CKSEL (or LOW.SUT_CKSEL in my case) to desired frequency (make sure you have read up on the side effects of this). 

La frecuencia utilizada en el ejemplo no es una norma interna de la frecuencia de reloj así que me voy a quedar con 2 mhz.

Resumen de las respuestas a mis propias preguntas

  1. Lo que he hecho mal/¿qué está pasando aquí? Respuesta: en realidad no cambiar la frecuencia de reloj a la frecuencia de reloj en el tutorial que se tradujo en una velocidad en baudios diferente a lo que se esperaba que poner el software de terminal (Masilla) fuera de sincronización con el MCU
  2. ¿Por qué el tutorial original no #define F_CPU? Respuesta: Aún no está del todo seguro, pero mi conjetura sería que se define en un fichero makefile no se da en el tutorial y que el autor no estaba haciendo uso de un IDE como Atmel Studio
  3. ¿Por qué la configuración de la velocidad en baudios a 2500 solucionar el problema? (Sospecho que esto va a ser contestado si a la pregunta 1 es contestada) Respuesta: por Suerte adivinar un número cercano a la velocidad en baudios del Atmega16

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X