Kami berteman STM32 dengan layar LCD 1604 di bus I2C (perpustakaan HAL)

Halo, Habr!

Pada artikel ini saya ingin berbicara tentang pengalaman saya menghubungkan layar LCD ke mikrokontroler STM32 menggunakan perpustakaan HAL pada bus I2C.

gambar

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

gambar

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.

gambar

gambar

Di jendela yang sama, Anda dapat melihat jumlah kaki yang terhubung ke layar, dalam kasus saya ternyata seperti ini:

gambar

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.

gambar

Harap dicatat bahwa adaptor menghubungkan RX ke TX dan TX ke RX, jumper pada adaptor adalah 3.3V

gambar

Mari kita lihat lebih dekat cara bekerja dengan chip dan tampilan PCF8574T. Di bawah ini adalah diagram skematik modul dengan tampilan:

gambar

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";      
        //    UART	
        HAL_UART_Transmit(&huart5, (uint8_t*)info, strlen(info), HAL_MAX_DELAY);  
	/* &huart5 -   UART
	 * (uint8_t*)info -     
	 * strlen(info) -   
	 * HAL_MAX_DELAY - 
	 */
        //    
	for(uint16_t i = 0; i < 128; i++)              
	{
            // ,      i  
            res = HAL_I2C_IsDeviceReady(&hi2c1, i << 1, 1, HAL_MAX_DELAY);                   
	    //  , 
            if(res == HAL_OK)                              
	    {
	    	char msg[64];
	    	//   i,   ,     
                // 16 :
	    	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:

gambar

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:

gambar

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(;;) {
                // ,      lcd_addr                                                                                        
	        res = HAL_I2C_IsDeviceReady(&hi2c1, LCD_ADDR, 1, HAL_MAX_DELAY);               
	         //  ,     
                if(res == HAL_OK) break;                                                  
	    }
        //    1111 0000      0  3,    4  7
	uint8_t up = data & 0xF0;   
        //   ,  data   4                	
        uint8_t lo = (data << 4) & 0xF0;          
                                          
	uint8_t data_arr[4];
         // 4-7   ,  0-3   
	data_arr[0] = up|flags|BACKLIGHT|PIN_EN; 
         //  ,       0  
	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);   // 8  
  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)
{
    // *char    
    //    
	while(*str) 
        {                                   
                //    
		I2C_send((uint8_t)(*str), 1); 
                //     1               
                str++;                                     
        }
}

Setelah mengumpulkan semua fungsi ini bersama-sama, Anda dapat menulis:

  LCD_SendString("  Hello");
  I2C_send(0b11000000,0);   //  
  LCD_SendString("    Habr");

gambar

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:

gambar

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 20
Baris kedua adalah sel 40 hingga 60
Baris ketiga - sel dari 21 hingga 40
Baris keempat - sel dari 60 hingga 80,
yaitu jika Anda mengirim perintah

LCD_SendString("___________________1___________________2___________________3___________________4");

Kami mendapatkan yang berikut:

gambar

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);   //   1 
  LCD_SendString("  Hello Habr");
  I2C_send(0b11000000,0);   //   2 
  LCD_SendString(" STM32 + LCD 1602");
  I2C_send(0b10010100,0);   //   3 
  LCD_SendString(" +LCD 2004A");
  I2C_send(0b11010100,0);   //   4 
  LCD_SendString(" library HAL");

Hasil:

gambar

Itu mungkin semua dengan pajangan ini, tautan yang berguna berkat yang saya dapat mengatasinya:

  1. Kode terlihat sangat banyak di sini
  2. Tabel untuk konfigurasi tampilan tampak di sini
  3. Prosedurnya terlihat di sini

Program dan lembar data

PS: jangan lupa untuk menyesuaikan kecerahan layar terlebih dahulu.

All Articles