Risposta Atmega16 imprevista su UART


8

Risposta Atmega16 imprevista su UART

Breve riassunto del problema

Ho trasmesso un Atmega16 con un codice che dovrebbe comportare la restituzione di Atmega16 da qualsiasi carattere che gli invio tramite un terminale. Ricevo una risposta, ma raramente è il personaggio che ho inviato. Posso vedere l'output corretto modificando il baud rate ma non capisco perché il baud rate corretto funzioni.

Più dettaglio

Sto cercando di saperne di più sulla programmazione del firmware ai miei tempi perché mi diverto abbastanza. Finora nella programmazione del firmware che ho fatto in uni, ci sono stati dati file di codice scheletro che eseguono molte interfacce periferiche e sono stati configurati per noi, ma vorrei impararlo da solo. Ho alcune domande su cosa sto facendo qui, sparse in tutto il post, ma le farò alla fine. Se prendessi in considerazione incomprensioni o potenziali lacune nella mia conoscenza, apprezzerei molto qualsiasi input tu possa avere.

Il codice

Il codice che ho visualizzato sul mio Atmega16 è preso quasi riga per riga dal tutorial "Uso di USART in AVR-GCC" trovato in questa pagina . Tutto quello che ho aggiunto è #define per F_CPU. Il codice originale non aveva un #define per F_CPU, quindi il mio codice non sarebbe stato compilato in AtmelStudio 7. Qualcuno potrebbe spiegare perché l'autore non avrebbe definito F_CPU nel suo file originale? Immagino che stiano usando un altro strumento o compilatore diverso da Atmel Studio 7, ma non posso dirlo con certezza.

#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
    }
}

La configurazione dell'hardware

Foto della configurazione hardware

  • MCU: Atmega16;
  • Toolchain: Atmel Studio 7, lampeggiante con drago AVR;
  • Alimentazione: rotaia da 5 V presa da una scheda di sviluppo fornita dall'università (che viene presa dal computer USB). Condensatore a disco ceramico 100nF utilizzato per bypassare le linee elettriche della breadboard
  • Convertitore da USB a seriale: questo . TXD sul convertitore da USB a seriale collegato a RXD Atmega (Pin 15). RXD sul convertitore collegato a RXD su Atmega (Pin 14).
  • Software terminale: PuTTY (con baudrate di 9600).

    Prova delle risposte errate

    Per ribadire, l'Atmega dovrebbe restituire ciò che gli è stato inviato, ovvero OUTPUT dovrebbe essere esattamente lo stesso di INPUT.

    Uscita PuTTY

    INGRESSOPRODUZIONEf&f6z>d0spazio0X8

    Cattura dell'oscilloscopio

    Ho usato il mio Picoscope con decodifica seriale per verificare che l'Atmega stia ricevendo l'input corretto, che sembra essere. Ad esempio, quando premo il tasto 'f', viene ricevuto correttamente. L'uscita è ancora un '6' (o una e commerciale '&' a volte).

Acquisizione dell'ambito sul pin RX di Atmega16 che mostra che il carattere corretto viene inviato tramite il software del terminale ('f')

Acquisizione dell'ambito sul pin TX dell'Atmega16 che mostra che viene inviata una risposta indesiderata ('6')

Una soluzione su cui mi sono imbattuto è che non capisco

Se cambio il baudrate a 2500 in PuTTY, tutto viene visualizzato correttamente. Ho scelto questo valore a caso e non so perché funzioni (mi porta a credere di aver fatto un errore da qualche parte a che fare con il baudrate ma non vedo dove dato ho copiato il tutorial quasi esattamente ... I pensiero).

Domande

  1. Cosa ho fatto di sbagliato / cosa sta succedendo qui?
  2. Perché il tutorial originale non è #define F_CPU?
  3. Perché l'impostazione del baud rate su 2500 risolve il problema? (Sospetto che a questa risposta verrà data risposta alla domanda 1)

2
La semplice definizione di F_CPU su un certo valore non fa funzionare il micro a quella frequenza. F_CPU dovrebbe essere definito come la frequenza con cui hai configurato il micro per funzionare - ma non vedo alcuna prova che tu l'abbia configurato da nessuna parte ...
brhans

Domanda ben scritta. L'unica cosa che lo migliorerebbe sarebbe uno schema.
Blair Fonville,

+1 solo per il LUNTEXtavolo.
Arsenale,

Ho notato che non hai cristalli esterni sulla tua breadboard. Stai utilizzando l'orologio RC interno? Con quale frequenza ti aspetti che funzioni il processore?
scotty3785,

Grazie alla tua discussione su F_CPU ho fatto qualche indagine e ho giocato e pubblicato la soluzione. Immagino sia ovvio per te (come lo è ora per me ) ma potrebbe aiutare qualcun altro.
daviegravee,

Risposte:


0

L'ho capito! Grazie ai commenti su F_CPU in risposta all'OP ho svolto alcune indagini (questo potrebbe essere ovvio per tutti voi).

Breve riepilogo della soluzione

L'Atmega16 non funzionava alla frequenza che pensavo fosse perché non capivo come cambiare la sua frequenza di sistema. Controllando i fusibili in Atmel Studio ho potuto vedere che stavo funzionando a 2MHz (questa non è la frequenza di clock standard per quanto ne so, ma non entrerò in quello), e non a 7,3728 MHz come il tutorial.

F_CPU non modifica la frequenza di clock dell'MCU (Atmega16). La frequenza di Atmega16 non è stata modificata in 7,3728 MHz, in quanto era necessario per far funzionare l'esempio di codice. Funzionava ancora alla frequenza definita dai fusibili (2MHz in questo caso, più su questo in basso), quindi il calcolo della carta del baudrate desiderato differisce da quello effettivamente utilizzato.

Codice di lavoro

#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
    }
}

Più dettaglio

Baudrate desiderato vs quello che l'Atmega stava effettivamente facendo

Il baudrate desiderato (dal tutorial) era 9600, che è il baudrate che ho usato in PuTTY. Il baudrate effettivo può essere calcolato usando l'equazione evidenziata nella Tabella 60 (pagina 147) del foglio dati Atmega16.

Tabella delle equazioni per calcolare baudrate e UBRR da pagina 147 Atmega16 datasheet

Nell'esempio di codice BAUD_PRESCALEè UBRR nel calcolo. BAUD_PRESCALEviene valutato come 47 con i valori definiti per F_CPUe USART_BAUDRATE.

BAUD=foSc16(UBRR+1)
BAUD=2,000,00016(47+1)
BAUD2,604

E questa era la radice del problema. L'Atmega16 stava funzionando a 2MHz, il che significava che il valore di f_ {osc} era diverso dall'esempio del tutorial, che ha prodotto un baudrate di 2.604 rispetto a 9.600.

Si noti che f_osc è la frequenza di sistema effettiva dell'MCU, che non è determinata da F_CPU.

In modo che risponda anche alla mia terza domanda: cambiare il baudrate a 2.500 è stato fortunatamente abbastanza vicino al baudrate operativo dell'MCU che il terminale potrebbe interpretare correttamente i risultati.

Modifica della frequenza dell'MCU

Per modificare la frequenza dell'MCU in AtmelStudio 7, andare:

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 frequenza utilizzata nell'esempio non è una frequenza di clock interna standard, quindi resterò con 2MHz.

Riepilogo delle risposte alle mie domande

  1. Cosa ho fatto di sbagliato / cosa sta succedendo qui? Risposta : In realtà il tutorial non ha modificato la frequenza di clock con la frequenza di clock, il che ha comportato un baudrate diverso da quello che ci si aspettava che ha reso il software del terminale (PuTTY) non sincronizzato con l'MCU
  2. Perché il tutorial originale non è #define F_CPU? Risposta : Non sono ancora del tutto sicuro, ma la mia ipotesi sarebbe che sia definito in un makefile non fornito nel tutorial e che l'autore non stesse usando un IDE come Atmel Studio
  3. Perché l'impostazione del baud rate su 2500 risolve il problema? (Sospetto che a questa risposta verrà data risposta alla domanda 1) Risposta : fortunatamente indovinato un numero vicino al baudrate dell'Atmega16
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.