Unerwartete Atmega16-Antwort über UART
Ich habe einen Atmega16 mit Code geflasht, der dazu führen sollte , dass der Atmega16 jedes Zeichen zurücksendet, das ich über ein Terminal an ihn sende. Ich bekomme eine Antwort, aber es ist selten das Zeichen, das ich gesendet habe. Ich kann die korrekte Ausgabe sehen, indem ich die Baudrate ändere, aber ich verstehe nicht, warum die richtige Baudrate funktioniert.
Ich versuche, in meiner Freizeit mehr über Firmware-Programmierung zu lernen, weil es mir großen Spaß macht. Bisher haben wir in der Firmware-Programmierung, die ich an der Uni durchgeführt habe, Skelettcodedateien erhalten, die einen Großteil der Peripherieschnittstellen übernehmen und für uns einrichten, aber ich würde das gerne selbst lernen. Ich habe ein paar Fragen darüber, was ich hier tue, die über den gesamten Beitrag verstreut sind, aber ich werde sie am Ende auflisten. Wenn Sie Missverständnisse oder mögliche Wissenslücken aufgreifen, würde ich mich sehr über Ihren Beitrag freuen.
Der Code, den ich auf meinen Atmega16 geflasht habe, stammt fast Zeile für Zeile aus dem Tutorial „Using the USART in AVR-GCC“ auf dieser Seite . Alles, was ich hinzugefügt habe, ist das #define für F_CPU. Der ursprüngliche Code hatte kein #define für F_CPU, sodass mein Code nicht in AtmelStudio 7 kompiliert werden konnte. Könnte jemand erklären, warum der Autor F_CPU nicht in seiner ursprünglichen Datei definiert hätte? Ich vermute, dass sie möglicherweise ein anderes Tool oder einen anderen Compiler als Atmel Studio 7 verwendet haben, aber ich kann es nicht mit Sicherheit sagen.
#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
}
}
Terminalsoftware: PuTTY (mit Baudrate 9600).
Um es noch einmal zu wiederholen, der Atmega sollte zurückgeben, was an ihn gesendet wurde, dh OUTPUT sollte genau das gleiche wie INPUT sein.
Ich habe mein Picoscope mit serieller Dekodierung verwendet, um zu überprüfen, ob der Atmega die richtige Eingabe erhält, die es zu sein scheint. Wenn ich zum Beispiel die 'f'-Taste drücke, wird es korrekt empfangen. Die Ausgabe ist immer noch eine '6' (oder gelegentlich ein kaufmännisches Und '&').
Wenn ich in PuTTY die Baudrate auf 2500 ändere, wird alles korrekt angezeigt. Ich habe diesen Wert zufällig gewählt und weiß nicht, warum es funktioniert (es lässt mich glauben, dass ich irgendwo einen Fehler gemacht habe, der mit der Baudrate zu tun hat, aber ich sehe nicht, wo ich das Tutorial fast genau kopiert habe ... I habe gedacht).
Ich habe es herausgefunden! Dank der Kommentare zu F_CPU als Antwort auf das OP habe ich einige Nachforschungen angestellt (dies könnte für Sie alle offensichtlich sein).
Der Atmega16 lief nicht mit der Frequenz, die ich dachte, weil ich nicht verstand, wie man seine Systemfrequenz ändert. Durch Überprüfen der Sicherungen in Atmel Studio konnte ich sehen, dass ich mit 2 MHz lief (dies ist meines Wissens nicht die Standardtaktfrequenz, aber ich werde nicht darauf eingehen) und nicht 7,3728 MHz wie im Tutorial.
F_CPU ändert nicht die Taktfrequenz der MCU (der Atmega16). Die Frequenz des Atmega16 wurde nicht auf 7,3728 MHz geändert, wie es notwendig war, um das Codebeispiel zum Laufen zu bringen. Es lief immer noch mit der durch die Sicherungen definierten Frequenz (in diesem Fall 2 MHz, mehr dazu weiter unten), sodass die Papierberechnung der gewünschten Baudrate von der tatsächlich verwendeten abweicht.
#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
}
}
Die gewünschte Baudrate (aus dem Tutorial) war 9600, das ist die Baudrate, die ich in PuTTY verwendet habe. Die tatsächliche Baudrate kann mit der hervorgehobenen Gleichung in Tabelle 60 (Seite 147) des Atmega16-Datenblatts berechnet werden.
Im Codebeispiel BAUD_PRESCALE
geht UBRR in die Berechnung ein. wird als 47 mit den für und BAUD_PRESCALE
definierten Werten ausgewertet .F_CPU
USART_BAUDRATE
Und das war die Wurzel des Problems. Der Atmega16 wurde mit 2 MHz betrieben, was bedeutete, dass der Wert von f_{osc} anders war als im Tutorial-Beispiel, was zu einer Baudrate von 2.604 im Gegensatz zu 9.600 führte.
Beachten Sie, dass f_osc die tatsächliche Systemfrequenz der MCU ist, die nicht durch bestimmt wird F_CPU
.
Damit ist auch meine 3. Frage beantwortet: Das Ändern der Baudrate auf 2.500 war zum Glück nahe genug an der Betriebsbaudrate der MCU, dass das Terminal die Ergebnisse richtig interpretieren konnte.
Um die Frequenz der MCU in AtmelStudio 7 zu ändern, gehen Sie zu:
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).
Die im Beispiel verwendete Frequenz ist keine standardmäßige interne Taktfrequenz, daher bleibe ich bei 2 MHz.
brhans
Blair Fonville
Arsenal
scotty3785
daviegravee