Respons Atmega16 yang tidak terduga atas UART
Ringkasan masalah singkat
Saya telah menginstal Atmega16 dengan kode yang akan menghasilkan Atmega16 mengirim kembali karakter apa pun yang saya kirim kepadanya melalui terminal. Saya mendapat respons, tetapi jarang karakter yang saya kirim. Saya dapat melihat output yang benar dengan mengubah baud rate tetapi saya tidak mengerti mengapa baud rate yang benar bekerja.
Lebih detail
Saya mencoba mempelajari lebih lanjut tentang pemrograman firmware pada waktu saya sendiri karena saya sangat menikmatinya. Sejauh ini dalam pemrograman firmware yang telah saya lakukan di uni, kami telah diberi file kode kerangka yang melakukan banyak antarmuka periferal dan mengatur untuk kami, tetapi saya ingin belajar ini sendiri. Saya punya beberapa pertanyaan tentang apa yang saya lakukan di sini yang ditaburi di seluruh posting tapi saya akan memerinci mereka di akhir. Jika Anda memahami kesalahpahaman atau potensi kesenjangan dalam pengetahuan saya, saya akan sangat menghargai setiap masukan yang mungkin Anda miliki.
Kode
Kode yang saya telah flash ke Atmega16 saya diambil garis hampir untuk baris dari tutorial 'Menggunakan USART dalam AVR-GCC' yang ditemukan di halaman ini . Yang saya tambahkan adalah #define untuk F_CPU. Kode asli tidak memiliki #define untuk F_CPU sehingga kode saya tidak dapat dikompilasi di AtmelStudio 7. Adakah yang bisa menjelaskan mengapa penulis tidak mendefinisikan F_CPU dalam file asli mereka? Saya menduga mereka mungkin telah menggunakan beberapa alat atau kompiler selain Atmel Studio 7 tapi saya tidak bisa mengatakannya dengan pasti.
#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
}
}
Pengaturan perangkat keras
- MCU: Atmega16;
- Toolchain: Atmel Studio 7, berkedip dengan AVR dragon;
- Catu daya: 5V rel diambil dari papan pengembangan yang disediakan universitas (yang diambil dari komputer USB). Kapasitor cakram keramik 100nF digunakan untuk memotong kabel listrik papan tempat memotong roti
- Konverter USB ke serial: Yang ini . TXD pada USB ke serial converter yang terhubung ke RXD Atmega (Pin 15). RXD pada konverter terhubung ke RXD pada Atmega (Pin 14).
Perangkat lunak terminal: Putty (dengan baudrate 9600).
Bukti tanggapan yang salah
Untuk mengulangi, Atmega harus mengembalikan apa yang dikirim kepadanya yaitu OUTPUT harus sama persis dengan INPUT.
Keluaran Putty
Tangkapan Osiloskop
Saya telah menggunakan Picoscope saya dengan decoding serial untuk memeriksa apakah Atmega menerima input yang benar, yang tampaknya memang demikian. Misalnya, ketika saya menekan tombol 'f', itu diterima dengan benar. Output masih '6' (atau ampersand '&' pada kesempatan).
Perbaikan saya menemukan bahwa saya tidak mengerti
Jika saya mengubah baudrate ke 2500in Putty, semuanya ditampilkan dengan benar. Saya memilih nilai ini secara acak dan saya tidak tahu mengapa itu bekerja (itu membuat saya percaya bahwa saya telah membuat kesalahan di suatu tempat dengan baudrate tapi saya tidak melihat di mana mengingat saya menyalin tutorial hampir persis ... saya pikir).
Pertanyaan
- Apa yang telah saya lakukan salah / apa yang terjadi di sini?
- Mengapa tutorial asli tidak menentukan # F_CPU?
- Mengapa pengaturan baud rate ke 2500 memperbaiki masalah? (Saya menduga ini akan dijawab jika pertanyaan 1 dijawab)
Jawaban:
Saya sudah menemukan jawabannya! Berkat komentar tentang F_CPU dalam menanggapi OP saya melakukan investigasi (ini mungkin jelas bagi Anda semua).
Ringkasan solusi singkat
Atmega16 tidak berjalan pada frekuensi yang saya pikir itu karena saya tidak mengerti bagaimana mengubah frekuensi sistemnya. Dengan memeriksa sekering di Atmel Studio saya bisa melihat saya berjalan pada 2MHz (ini bukan frekuensi clock standar sejauh yang saya ketahui tetapi saya tidak akan membahasnya), dan bukan 7.3728MHz seperti tutorialnya.
F_CPU tidak mengubah frekuensi jam MCU (Atmega16). Frekuensi Atmega16 tidak diubah menjadi 7.3728MHz seperti yang diperlukan untuk mendapatkan contoh kode untuk bekerja. Itu masih berjalan pada frekuensi yang ditentukan oleh sekering (2MHz dalam hal ini, lebih lanjut tentang ini di bawah) sehingga perhitungan kertas baudrate yang diinginkan berbeda dari apa yang sebenarnya digunakan.
Kode kerja
Lebih detail
Baudrate yang diinginkan vs apa yang sebenarnya dilakukan Atmega
Baudrate yang diinginkan (dari tutorial) adalah 9600, yang merupakan baudrate yang saya gunakan di Putty. Baudrate aktual dapat dihitung menggunakan persamaan yang disorot pada Tabel 60 (halaman 147) dari lembar data Atmega16.
Dalam kode contohnya
BAUD_PRESCALE
adalah UBRR dalam perhitungan.BAUD_PRESCALE
dievaluasi sebagai 47 dengan nilai yang ditentukan untukF_CPU
danUSART_BAUDRATE
.Dan ini adalah akar masalahnya. Atmega16 beroperasi pada 2MHz, yang berarti nilai f_ {osc} berbeda dengan contoh tutorial, yang menghasilkan baudrate 2.604 dibandingkan dengan 9.600.
Perhatikan bahwa f_osc adalah sebenarnya frekuensi sistem MCU, yang tidak ditentukan oleh
F_CPU
.Jadi itu juga menjawab pertanyaan ke-3 saya: mengubah baudrate ke 2.500 untungnya cukup dekat dengan baudrate operasi MCU sehingga terminal dapat menginterpretasikan hasil dengan benar.
Mengubah frekuensi MCU
Untuk mengubah frekuensi MCU di AtmelStudio 7, buka:
Frekuensi yang digunakan dalam contoh ini bukan frekuensi clock internal standar jadi saya akan tetap menggunakan 2MHz.
Ringkasan jawaban untuk pertanyaan saya sendiri
sumber