Halo, Habr!Pada artikel ini saya ingin berbicara tentang pengalaman saya menghubungkan layar LCD ke mikrokontroler STM32 menggunakan perpustakaan HAL pada bus I2C.
Saya akan menghubungkan layar 1602 dan 2004. Keduanya memiliki adaptor I2C yang disolder berdasarkan chip PCF8574T. Papan debug akan menjadi Nucleo767ZI , dan lingkungan pengembangan akan menjadi STM32CubeIDE 1.3.0.Saya tidak akan berbicara secara rinci tentang prinsip pengoperasian bus I2C, saya sarankan Anda untuk melihat di sini dan di sini .Kami membuat proyek, pilih papan debug: Kami
menunjukkan bahwa kami akan menggunakan I2C1. Saya juga akan menghubungkan UART5 untuk berkomunikasi dengan board, ini diperlukan untuk menerima informasi dari board tentang alamat display.
Di jendela yang sama, Anda dapat melihat jumlah kaki yang terhubung ke layar, dalam kasus saya ternyata seperti ini:
Untuk memulai, hubungkan hanya satu tampilan, saya akan mulai dengan 1602. Juga, saya akan menghubungkan adaptor USB-UART CH340, yang dikenal dengan driver arduin berpengalaman, untuk menerima data dari papan.
Harap dicatat bahwa adaptor menghubungkan RX ke TX dan TX ke RX, jumper pada adaptor adalah 3.3V
Mari kita lihat lebih dekat cara bekerja dengan chip dan tampilan PCF8574T. Di bawah ini adalah diagram skematik modul dengan tampilan:
Chip PCF8574T memiliki fungsionalitas yang mirip dengan register geser 74hc595 - ia menerima byte melalui antarmuka I2C dan memberikan nilai bit yang sesuai ke outputnya (P0-P7).Pertimbangkan pin microcircuit yang terhubung ke monitor dan apa yang menjadi tanggung jawabnya:- Terminal P0 dari rangkaian mikro terhubung ke terminal RS dari tampilan, yang bertanggung jawab untuk menerima data tampilan (1) atau instruksi pengoperasian tampilan (0);
- Pin P1 terhubung ke R \ W, jika 1 - tulis data ke layar, 0 - baca;
- Terminal P2 terhubung ke CS - terminal, setelah perubahan status yang sedang dibaca;
- Kesimpulan P3 - kontrol lampu latar;
- Kesimpulan P4 - P7 digunakan untuk mengirimkan data ke layar.
Beberapa perangkat dapat dihubungkan ke satu bus I2C secara bersamaan. Agar dapat mengakses perangkat tertentu, masing-masing memiliki alamat sendiri, pertama-tama kita akan mengetahuinya. Jika kontak A1, A2 dan A3 pada papan adaptor tidak disegel, maka alamat kemungkinan besar akan 0x27, tetapi lebih baik untuk memeriksa. Untuk melakukan ini, kami akan menulis fungsi kecil yang akan menunjukkan alamat semua perangkat yang terhubung ke bus I2C:void I2C_Scan ()
{
HAL_StatusTypeDef res;
char info[] = "Scanning I2C bus...\r\n";
HAL_UART_Transmit(&huart5, (uint8_t*)info, strlen(info), HAL_MAX_DELAY);
for(uint16_t i = 0; i < 128; i++)
{
res = HAL_I2C_IsDeviceReady(&hi2c1, i << 1, 1, HAL_MAX_DELAY);
if(res == HAL_OK)
{
char msg[64];
snprintf(msg, sizeof(msg), "0x%02X", i);
HAL_UART_Transmit(&huart5, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart5, (uint8_t*)"\r\n", 2, HAL_MAX_DELAY);
}
else HAL_UART_Transmit(&huart5, (uint8_t*)".", 1, HAL_MAX_DELAY);
}
HAL_UART_Transmit(&huart5, (uint8_t*)"\r\n", 2, HAL_MAX_DELAY);
}
Fungsi ini mengumpulkan semua alamat mulai dari 0 hingga 127 dan jika respons diterima dari alamat ini, ia mengirim nomor alamat dalam bentuk heksadesimal ke UART.Untuk berkomunikasi dengan dewan, saya menggunakan program Rayap. Secara default, kecepatan UART mikrokontroler diatur ke 115200, Anda harus mengatur yang sama dalam rayap. Kami memanggil fungsi di bagian utama program, mem-flash papan dan menghubungkan rayap ke mikrokontroler kami:
Titik-titik menunjukkan semua alamat yang jawabannya tidak diterima. Alamat pada layar saya adalah 0x26, karena saya menyolder jumper A0. Sekarang sambungkan tampilan paralel kedua dengan tampilan pertama, dan lihat apa yang akan diberikan oleh program:
Kami memiliki dua alamat: 0x26 (tampilan 1602) dan 0x27 (tampilan 2004). Sekarang tentang cara bekerja dengan tampilan. Mikrokontroler mengirimkan byte alamat, dan semua perangkat yang terhubung ke bus memeriksanya dengan milik mereka. Jika cocok, maka modul memulai komunikasi dengan mikrokontroler. Pertama-tama, Anda perlu mengkonfigurasi tampilan: di mana jumlah karakter akan pergi dan ke arah mana, bagaimana kursor akan berperilaku, dll. Setelah itu, sudah dimungkinkan untuk mengirimkan informasi untuk ditampilkan ke layar. Keunikannya adalah kita hanya dapat menggunakan 4 bit untuk mengirimkan informasi, mis. data harus dipecah menjadi dua bagian. Data disimpan dalam bit tinggi (4-7), dan bit rendah digunakan untuk menunjukkan apakah lampu latar akan menyala (3 bit), apakah data datang untuk output, atau pengaturan tampilan (output RS, 0 bit), dan 2 bit, oleh perubahan bacaan yang terjadi, yaitue untuk mengirim 1 byte data yang Anda butuhkan untuk mengirim 4 byte - byte pertama akan berisi 4 bit informasi, bit ke-2 untuk menyatakan 1, byte ke-2 adalah pengulangan tanggal 1, hanya bit ke-2 untuk menyatakan 0. Byte ke-3 dan ke-4 sama, hanya berisi bagian kedua dari data. Kedengarannya agak tidak bisa dimengerti, saya akan menunjukkan kepada Anda sebuah contoh:void I2C_send(uint8_t data, uint8_t flags)
{
HAL_StatusTypeDef res;
for(;;) {
res = HAL_I2C_IsDeviceReady(&hi2c1, LCD_ADDR, 1, HAL_MAX_DELAY);
if(res == HAL_OK) break;
}
uint8_t up = data & 0xF0;
uint8_t lo = (data << 4) & 0xF0;
uint8_t data_arr[4];
data_arr[0] = up|flags|BACKLIGHT|PIN_EN;
data_arr[1] = up|flags|BACKLIGHT;
data_arr[2] = lo|flags|BACKLIGHT|PIN_EN;
data_arr[3] = lo|flags|BACKLIGHT;
HAL_I2C_Master_Transmit(&hi2c1, LCD_ADDR, data_arr, sizeof(data_arr), HAL_MAX_DELAY);
HAL_Delay(LCD_DELAY_MS);
}
Mari kita bereskan. Pada awalnya ada variabel yang menyimpan alamat tampilan, dan bit pengaturan yang harus dikirim setiap kali bersama dengan data. Dalam fungsi pengiriman, kami pertama-tama memeriksa apakah ada modul pada alamat yang direkam. Jika menerima pesan HAL_OK, kami mulai membentuk byte untuk dikirim. Pada awal byte yang akan kami kirim, perlu dibagi menjadi dua bagian, tulis keduanya ke bit-bit tinggi. Misalkan kita ingin tampilan untuk menampilkan karakter 's', dalam sistem biner itu adalah 1110011 ( kalkulator) Menggunakan operasi logis & kami menulis = 01110000 ke dalam variabel, mis. tulis hanya bit yang paling signifikan. Bit urutan rendah digeser ke kiri oleh 4 karakter di awal, dan kemudian ditulis ke dalam variabel lo = 00110000. Selanjutnya, kita membentuk array 4 byte yang berisi informasi tentang karakter yang akan ditampilkan. Sekarang kami menetapkan bit konfigurasi (0-3 bit) ke byte yang ada. Setelah itu, kami mengirim byte alamat dan 4 byte informasi ke layar menggunakan fungsi HAL_I2C_Master_Transmit ();Tapi jangan buru-buru mengunduh program, karena pada awalnya Anda perlu mengatur pengaturan tampilan. Situs ini memiliki tabel terjemahan yang sangat baik dengan perintah untuk menyesuaikan tampilan. Setelah memeriksanya dengan dokumentasi, saya datang ke pengaturan berikut yang optimal untuk diri saya sendiri: I2C_send(0b00110000,0);
I2C_send(0b00000010,0);
I2C_send(0b00001100,0);
I2C_send(0b00000001,0);
Kami menempatkan perintah-perintah ini sebelum awal loop tak terbatas, sehingga pengaturan dikirim sekali sebelum memulai bekerja (seperti pengaturan batal di arduinki). Fungsi I2C_send, selain byte, mengharuskan Anda menentukan apakah pengaturan tampilan atau data akan dikirim. Jika argumen kedua dari fungsi adalah 0, maka pengaturan, dan jika 1, maka data.Dan sentuhan terakhir - Anda memerlukan fungsi yang akan mengirim tenggat waktu karakter-demi-karakter. Semuanya sangat sederhana di sini:void LCD_SendString(char *str)
{
while(*str)
{
I2C_send((uint8_t)(*str), 1);
str++;
}
}
Setelah mengumpulkan semua fungsi ini bersama-sama, Anda dapat menulis: LCD_SendString(" Hello");
I2C_send(0b11000000,0);
LCD_SendString(" Habr");
Ya, kami berhasil menemukan layar 1602, sekarang 2004. Perbedaan di antara mereka sangat minim, bahkan kode ini akan berfungsi dengan baik. Semua perbedaan bermuara pada pengorganisasian alamat sel pada tampilan. Di kedua layar, memori berisi 80 sel, pada layar 1602, 16 sel pertama bertanggung jawab untuk baris pertama, dan sel 40 hingga 56 bertanggung jawab untuk baris kedua. Sel memori yang tersisa tidak ditampilkan, jadi jika Anda mengirim 17 karakter ke layar, yang terakhir tidak akan ditransfer pada baris kedua, dan akan direkam dalam sel memori yang tidak memiliki output ke layar. Sedikit lebih jelas, memori diatur sebagai berikut:
Untuk menggunakan umpan baris, saya menggunakan perintah I2C_send (0b11000000,0); , itu hanya pergi ke 40 sel. Tampilan 2004 lebih menarik.Baris pertama adalah sel 1 hingga 20Baris kedua adalah sel 40 hingga 60Baris ketiga - sel dari 21 hingga 40Baris keempat - sel dari 60 hingga 80,yaitu jika Anda mengirim perintahLCD_SendString("___________________1___________________2___________________3___________________4");
Kami mendapatkan yang berikut:
Untuk mengatur transisi antar baris, Anda harus memindahkan kursor ke sel memori yang diinginkan secara manual, atau Anda dapat secara terprogram melengkapi fungsi tersebut. Sejauh ini saya telah membahas versi manual: I2C_send(0b10000000,0);
LCD_SendString(" Hello Habr");
I2C_send(0b11000000,0);
LCD_SendString(" STM32 + LCD 1602");
I2C_send(0b10010100,0);
LCD_SendString(" +LCD 2004A");
I2C_send(0b11010100,0);
LCD_SendString(" library HAL");
Hasil:
Itu mungkin semua dengan pajangan ini, tautan yang berguna berkat yang saya dapat mengatasinya:- Kode terlihat sangat banyak di sini
- Tabel untuk konfigurasi tampilan tampak di sini
- Prosedurnya terlihat di sini
Program dan lembar dataPS: jangan lupa untuk menyesuaikan kecerahan layar terlebih dahulu.