Respons Atmega16 yang tidak terduga atas UART

8

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

Foto 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

    MEMASUKKANKELUARANf&f6z>d0ruang0x8

    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).

Cakupan penangkapan pada pin RX Atmega16 menunjukkan bahwa karakter yang benar sedang dikirim melalui perangkat lunak terminal ('f')

Pengambilan lingkup pada pin TX dari Atmega16 menunjukkan bahwa respons yang tidak diinginkan dikirim kembali ('6')

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

  1. Apa yang telah saya lakukan salah / apa yang terjadi di sini?
  2. Mengapa tutorial asli tidak menentukan # F_CPU?
  3. Mengapa pengaturan baud rate ke 2500 memperbaiki masalah? (Saya menduga ini akan dijawab jika pertanyaan 1 dijawab)
daviegravee
sumber
2
Cukup mendefinisikan F_CPU ke beberapa nilai tidak membuat mikro berjalan pada frekuensi itu. F_CPU harus didefinisikan sebagai frekuensi di mana Anda telah mengkonfigurasi mikro untuk menjalankan - tapi saya tidak melihat bukti bahwa Anda telah mengkonfigurasi ini di mana saja ...
brhans
Pertanyaan yang ditulis dengan baik. Satu-satunya hal yang akan memperbaikinya adalah skema.
Blair Fonville
+1 hanya untuk L.SEBUAHTEXmeja.
Arsenal
Saya perhatikan bahwa Anda tidak memiliki kristal eksternal di papan tempat memotong roti Anda. Apakah Anda menggunakan jam RC internal? Berapa frekuensi Anda berharap prosesor berjalan?
scotty3785
Berkat diskusi Anda tentang F_CPU, saya melakukan investigasi dan bermain-main dan memposting solusinya. Saya membayangkan itu jelas bagi Anda (seperti bagi saya sekarang ) tetapi mungkin membantu orang lain.
daviegravee

Jawaban:

0

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

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

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.

Daftar persamaan untuk menghitung baudrate dan UBRR dari halaman 147 Atmega16 datasheet

Dalam kode contohnya BAUD_PRESCALEadalah UBRR dalam perhitungan. BAUD_PRESCALEdievaluasi sebagai 47 dengan nilai yang ditentukan untuk F_CPUdan USART_BAUDRATE.

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

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:

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). 

Frekuensi yang digunakan dalam contoh ini bukan frekuensi clock internal standar jadi saya akan tetap menggunakan 2MHz.

Ringkasan jawaban untuk pertanyaan saya sendiri

  1. Apa yang telah saya lakukan salah / apa yang terjadi di sini? Menjawab : Tidak benar-benar mengubah frekuensi jam ke frekuensi jam dalam tutorial yang menghasilkan baudrate berbeda dengan apa yang diharapkan yang membuat perangkat lunak terminal (Putty) tidak sinkron dengan MCU
  2. Mengapa tutorial asli tidak menentukan # F_CPU? Menjawab : Masih belum sepenuhnya yakin tetapi dugaan saya akan didefinisikan dalam makefile yang tidak diberikan dalam tutorial dan bahwa penulis tidak menggunakan IDE seperti Atmel Studio
  3. Mengapa pengaturan baud rate ke 2500 memperbaiki masalah? (Saya menduga ini akan dijawab jika pertanyaan 1 dijawab) Jawaban : Untungnya menebak nomor yang dekat dengan baudrate Atmega16
daviegravee
sumber