Tampilan grafik, termasuk yang dari tipe OLED, yang paling terwakili di pasar kami oleh Winstar, memiliki permintaan yang jauh lebih rendah sehubungan dengan huruf kecil dan publikasi tentang penggunaannya juga jauh lebih sedikit. Sementara itu, ini adalah tampilan OLED grafis yang, karena kurangnya pengikatan pada tabel font dari pola yang telah ditentukan, memberikan cara terbaik untuk mendapatkan perangkat tampilan ergonomis untuk berbagai kebutuhan. Selain itu, ternyata mode grafis pada pengontrol WS0010 lebih mudah dimulai dan berfungsi lebih stabil daripada mode teks.
Sebelum melanjutkan ke pertimbangan tampilan grafik aktual, kami akan mempertimbangkan masalah hijau dengan masalah beralih pada mode teks dari pengontrol WS0010, yang menerima solusi yang tidak terduga dan jelas (oh, di mana mataku!).
Menyelesaikan Masalah Mode Teks WS0010
Diketahui bahwa tampilan garis Winstar memiliki masalah stabilitas selama inisialisasi. Ngomong-ngomong, ternyata ini tidak unik untuk "orang Cina terkutuk": sampel Newhaven Display 16x2, yang saya peroleh dengan susah payah, terletak di sisi lain dunia, secara eksternal merupakan salinan lengkap Winstar, kecuali untuk lokasi beberapa tulisan dan nama perusahaan pada blotch ( bentuk dan font yang sama):

Mengandung, seperti yang tertulis dalam lembar data, pengontrol "sebanding LCD" tertentu, layar ini berperilaku sama persis dengan orang Cina dan memiliki kelemahan yang sama. Jelas, Anda tidak boleh menghabiskan waktu memeriksa perusahaan lain, seperti Midas: menilai dari
publikasi ini, itu tidak akan bisa dilakukan tanpa kerja sama internasional. Aturan ekonomi global!
Kesulitan mode teks dinyatakan dalam fakta bahwa ketika memulai (misalnya, ketika me-reboot atau mengatur ulang program pengontrol pengendali secara manual), sampah dapat muncul pada layar, dan garis 0 dan 1 secara acak mengubah tempat. Percobaan menunjukkan bahwa itu tidak tergantung pada metode inklusi (8-bit atau 4-bit). Masalah ini sangat akut ketika reboot perangkat lunak berkala diperlukan, misalnya, oleh Watchdog-timer.
Bagian dari masalah adalah sikap rapi terhadap kekuasaan (dari sumber yang terpisah, dan sama sekali tidak dari USB Arduino), dan reboot terpisah dengan mematikan dan menghidupkan layar setelah memulai program kontrol (lihat
publikasi penulis
sebelumnya ). Ternyata, penulis baris-baris ini bukan satu-satunya yang mengusulkan solusi serupa untuk masalah: penulis add-on
LuquidCrystal bernama
WinstarOLED juga termasuk pw_pin khusus di dalamnya, dengan mana daya tampilan terdistorsi pada saat program dimulai.
Tapi ini semua, tentu saja, inisiatif dan setengah langkah. Seseorang SeregaB menemukan cara yang radikal (lihat
publikasi tentang easyelectronics.ru - terima kasih kepada
Tomasina untuk tipnya). Bahkan, ia mengajukan tugas yang sama sekali berbeda: belajar cara bekerja hanya dengan mode grafis daripada mode teks. Mencoba beralih di antara mode, ia dengan cepat menemukan bahwa "
beralih ke mode grafis adalah normal, dan dari gambar ke" teks "itu sangat canggung ." Lalu dia ingat bahwa "
dulu, dulu sekali, ketika DShs masih dicetak di atas kertas, di beberapa DShs di HD44780 saya membaca bahwa beralih mode hanya boleh dilakukan ketika layar mati ." Dan itu berhasil.
Dari publikasi yang dikutip, saya hanya akan mereproduksi dua prosedur switching di sini, sedikit mengadaptasinya untuk digunakan dengan LuquidCrystal (instance kelas disebut OLED1 di sini).
Beralih ke mode grafis:
OLED1.command(0x08);// OLED1.command(0x1F);// OLED1.command(0x01);// (.. clear()) OLED1.command(0x08|0x04);//
Beralih ke mode teks:
OLED1.command(0x08);// OLED1.command(0x17);// OLED1.command(0x01);// (.. clear()) OLED1.command(0x04 | 0x08);//
Seperti yang akan kita lihat nanti, prosedur pertama tidak benar-benar diperlukan: WS0010 beralih ke mode grafis dari setengah tendangan, cukup kirim perintah 0x1F ke sana. Tetapi urutan kedua dari perintah sangat banyak terjadi. Untuk sampel, itu dimasukkan langsung ke dalam sketsa menggunakan LuquidCrystal dalam formulir ini:
void reset_textmode() // { OLED1.command(0x08);// OLED1.command(0x17);// OLED1.command(0x01);// OLED1.command(0x04 | 0x08);// }
Kemudian fungsi ini dipanggil dalam pengaturan tepat setelah inisiasi perpustakaan:
. . . . . OLED1.begin(16,2); //16 2 reset_textmode(); // clear() . . . . .
Jika Anda memasukkan beberapa penundaan (500) sebelum ini, demonstrasi menjadi sangat jelas: setelah menekan tombol reset papan Arduino di layar, seperti biasa, sampah muncul, tetapi hanya sesaat: setelah fungsi dipicu, layar dibersihkan dan semua garis kembali ke tempatnya .
Fungsi berfungsi seperti itu, tetapi untuk kenyamanan, saya mengganti konten fungsi LiquidCrystalRus :: clear () dalam file perpustakaan LiquidCrystalRus_OLED.cpp yang ditingkatkan yang dibahas sebelumnya dengan urutan perintah ini (saya ingatkan Anda bahwa
Anda dapat mengunduhnya dari situs penulis). Tidak ada menunggu perintah untuk dieksekusi di perpustakaan, oleh karena itu, untuk keandalan, setelah setiap perintah ada penundaan 100 ΞΌs dimasukkan dalam gaya umum perpustakaan. Dalam sketsa menggunakan varian LiquidCrystalRus_OLED ini, pada awal setup, perlu memanggil fungsi clear (), dan pada saat yang sama akan menghapus layar.
CatatanAda satu masalah dengan membersihkan layar: dalam lembar data dari tabel perintah dicatat bahwa perintah 0x01 dapat bertahan selama 6,2 ms βketika fsp atau fosc = 250KHzβ. Apa jenis "fsp atau fosc" sebenarnya dalam pengendali tertentu, mereka terlalu malas untuk menulis, tetapi dalam kasus apa pun, bahkan jika itu megahertz, penundaan untuk perintah ini harus signifikan (dan penulis LiquidCrystal menyebutkan ini). Namun, dalam praktiknya, ternyata tim kebersihan bekerja sendiri jika tidak ada penundaan sama sekali. Jadi saya tidak mengerti, tetapi bertindak berdasarkan aturan pemrograman yang terkenal: "berfungsi - jangan sentuh!".
Sekarang mari kita akhirnya berurusan dengan mode grafis.
Mode grafis dalam teks menampilkan WEH001602
Untuk memulainya, saya mencoba mengalihkan tampilan teks yang saya punya WEH001602BG ke mode grafis. Perhatikan bahwa tampilan grafis 100x16 dan teks (konfigurasi 20x2, 16x2 hanya memiliki lebih sedikit titik horizontal) memiliki matriks yang identik, hanya tampilan teks yang dipisahkan oleh interval dalam keakraban. Ini sangat membatasi penggunaan mode grafis dalam tampilan teks, dan bahkan lebih banyak mode teks dalam grafik. Tetapi untuk menguji cara kerjanya, Anda dapat menggunakan salah satunya.
Layar bersama dengan DS1307 terhubung ke Arduino Nano sesuai dengan skema berikut:

Menurut skema yang sama, kami akan menghubungkan tampilan grafis di masa depan. Warna abu-abu dalam diagram menunjukkan koneksi layar kedua, jika perlu.
Untuk beralih ke mode grafis, Anda dapat menggunakan prosedur yang ditingkatkan dari bagian sebelumnya, tetapi fungsi sederhana dari satu perintah berfungsi:
. . . . . #define LCD_SETGRAPHICMODE 0x1f LiquidCrystal lcd(9, 4, 8, 7, 6, 5); void setGraphicMode(){ lcd.command(LCD_SETGRAPHICMODE); } . . . . .
Kami tidak memerlukan meja Rusia di sini, oleh karena itu, LiquidCrystal standar (tidak diluruskan) digunakan, yang bekerja dengan sempurna dalam mode grafis. Agar tidak dipusingkan dengan debugging semua opsi perpustakaan, dalam kasus ketika teks dan tampilan grafis dimasukkan secara paralel, maka untuk setiap saya menggunakan perpustakaan saya sendiri (untuk upgrade teks Rus_OLED, untuk grafis normal). Dalam hal ini, koneksi masih dapat dibuat ke kaki pengontrol yang sama, dengan pengecualian pin keluaran E, menurut diagram di atas.
Lebih lanjut, saya sebagian menggunakan pencapaian penulis perpustakaan WinstarOLED yang disebutkan (dalam dirinya sendiri, add-on untuk LuquidCrystal ini, menurut pendapat saya, belum selesai, dan tidak praktis untuk menggunakannya sebagai). Dia memperkenalkan fungsi yang nyaman untuk mengatur kursor grafis (kesalahan awal mengenai nilai
x maksimum diperbaiki di sini):
void setGraphicCursor( uint8_t x, uint8_t y ){ if( 0 <= x && x <= 99 ){ lcd.command(LCD_SETDDRAMADDR | x); } if( 0 <= y && y <= 1 ){ lcd.command(LCD_SETCGRAMADDR | y); } }
LCD_SETDDRAMADDR konstan didefinisikan dalam perpustakaan LiquidCrystal. Tampilan 100x16, seperti tampilan teks, dibagi menjadi dua baris, 0 dan 1, karena Anda hanya dapat mengambil dua nilai di sini. Dan koordinat horizontal
x bervariasi dari 0 hingga 99. Satu byte dikirim dengan perintah lcd.write (), bit-bit individual yang menentukan posisi bercahaya garis vertikal dengan panjang 8 poin. Posisi paling kiri di baris atas memiliki koordinat 0,0, paling kanan di bawah - 99,1. Selain itu, titik terendah akan sesuai dengan bit paling tidak signifikan, dan titik terendah - tertinggi.
Untuk kenyamanan penyandian gambar, saya menggambar piring di mana Anda dapat dengan cepat membuat kode yang diinginkan secara manual. Untuk tabel font lengkap, tentu saja, disarankan untuk menggunakan editor khusus (setidaknya ada sejuta derajat aktivitas amatir), tetapi 10 digit dengan urutan bit yang diinginkan lebih cepat diproses secara manual, terutama karena font yang dibuat secara otomatis seringkali masih harus diselesaikan dengan tangan. Sesuai dengan di atas, mesin terbang, misalnya, font nomor 2 10x16 akan dikodekan sebagai berikut:

Semua ini ditulis dalam bentuk dua dimensi:
const byte Data2[2][10]={{0x06,0x07,0x03,0x03,0x03,0x83,0xc3,0x63,0x3f,0x1e}, {0xf0,0xf8,0xcc,0xc6,0xc3,0xc1,0xc0,0xc0,0xc0,0xc0}};
Untuk setiap digit 0-9, array seperti itu dibuat: Data0, Data1, Data2, dan sebagainya. Untuk jam tangan, selain angka, Anda perlu titik ganda lainnya. Itu bisa dibuat lebih pendek:
const byte DataDP[2][2]={{0x70,0x70}, {0x1c,0x1c}};//
Karena pengontrol tidak tahu bagaimana "berkedip" dalam mode grafik, maka secara pemrograman perlu mengedipkan titik dua. Anda dapat memadamkan titik ganda hanya dengan menampilkan nol di posisi yang sesuai, tetapi untuk keseragaman saya membuat array terpisah
const byte DataDPclr[2][2]={{0x00,0x00}, {0x00,0x00}};// .
Untuk menampilkan setiap digit dan secara terpisah untuk titik ganda, fungsi terpisah ditulis:
void draw2 (byte x/* */) // β2β { for (byte i = x; i<x+10; i++){ setGraphicCursor(i, 0); lcd.write(Data2[0][ix]); setGraphicCursor(i, 1); lcd.write(Data2[1][ix]);} }
Semua fungsi adalah sama, tetapi menggunakan array yang berbeda, dan untuk titik ganda, batas lain dari loop juga digunakan. Ternyata tidak terlalu ekonomis dalam hal jumlah kode (lihat lebih lanjut tentang ini nanti), tetapi jelas dan mudah untuk memperbaiki kesalahan. Kesenjangan antara karakter diperhitungkan pada tahap output, menunjukkan posisi yang sesuai (
perpustakaan RTClib digunakan untuk membaca jam):
void loop() { DateTime clock = RTC.now(); if (clock.second()!=old_second) { uint8_t values; values=clock.hour()/10; // drawValPos(values,0); values=clock.hour()%10; // drawValPos(values,12); values=clock.minute()/10; // drawValPos(values,28); values=clock.minute()%10; //end drawValPos(values,40); if (clock.second()%2) drawDP(24); else drawDPclr(24); old_second=clock.second(); }//end if clocksecond }
Sepuluh digit dari 20 byte masing-masing akan menempati 200 byte dalam memori - sekitar 10% dari volumenya (dan font lebar adalah 16x16, seperti pada contoh di bawah ini, dan semuanya 16%). Fon satu bahasa penuh dengan ukuran ini, bersama-sama dengan angka, tanpa memperhitungkan segala macam tanda baca dan spesial. karakter, terdiri dari 62 (Inggris) hingga 74 (Rusia tanpa E) karakter, nilainya akan mengambil hampir setengah dari RAM ATmega328. Oleh karena itu, trik dengan fungsi array dan output secara terpisah untuk setiap karakter harus dibatalkan, dan lakukan seperti yang diharapkan. Artinya, font harus dibiarkan dalam memori program dan diunduh melalui PROGMEM, dan semua pola mesin terbang harus disusun sebagai array font tunggal, dan dimuat untuk output dengan nomor simbol dalam satu tabel. Jika tidak, tidak akan ada cukup memori dan kode program akan mengembang ke volume yang tidak terkendali. Di sini kita tidak akan membahas hal ini, karena dalam contoh sederhana kita semua ini tidak diperlukan - setiap kali kita akan terbatas pada sejumlah kecil karakter yang sangat diperlukan.
Karena teks sketsa GraphicOLED_DC1307 berukuran besar, saya tidak membawanya; Anda dapat mengunduhnya di
sini . Fungsi resetOLED disimpan dalam teks, yang mendistorsi daya tampilan ketika controller reboot (melalui pwrPin D2), tetapi tidak pernah diperlukan, sehingga dapat dihapus dengan aman. Hasil program ditunjukkan pada foto:

Sayangnya, tetap simultan dalam mode teks dan grafik dikecualikan, oleh karena itu, jika Anda ingin menggunakan ruang yang tersisa, Anda harus menggambar font Anda sendiri (masih ada ruang untuk sekitar 7 karakter font 5x7 di setiap baris).
Tampilan grafik WEG010016A
Ketika, akhirnya, tampilan grafik berurutan WEG010016AL tiba, saya mulai dengan mencoba memasukkannya ke mode teks untuk melihat apa yang terjadi.
Untuk memeriksa mode teks, sebuah program untuk mensimulasikan tampilan jam-kalender dengan sensor suhu eksternal, dijelaskan
dalam publikasi sebelumnya, telah diunduh. Hasilnya membuat saya ingat bahwa tampilan Winstar yang berbeda dapat diorientasikan secara berbeda sehubungan dengan konektor (dalam hal ini, WEG010016A memiliki konektor di bagian atas, untuk teks WEH001602B, yang kami gunakan di atas, di bawah, dan untuk tipe C di samping):

Kami akan berurusan dengan orientasi tampilan lebih lanjut, tetapi untuk sekarang kita akan melihat apa yang terjadi. Tapi ternyata tidak ada yang baik: mode teks (tentu saja, dilengkapi dengan kruk, yang dibahas pada awal artikel) bekerja dengan sempurna, tetapi dalam praktiknya tidak masuk akal karena kurangnya ruang antara karakter. Oleh karena itu, kami tidak akan berlama-lama di sana, tetapi melanjutkan ke pertimbangan mode grafis.
Prosedur pemasangan mode grafis itu sendiri sama dengan yang dibahas di atas untuk versi teks. Tetap berurusan dengan flip layar jika memiliki konektor di bagian atas layar. Tentu saja, Anda bisa membalikkan layar, tetapi posisi dengan konektor menghadap ke bawah menurut saya lebih alami dan nyaman. Selain itu, saat menggunakan jenis dengan konektor di samping, Anda mungkin perlu mengarahkan konektor ke kanan daripada ke kiri. Untuk orientasi "terbalik", perlu untuk mengubah gambar - yaitu, menukar posisi horisontal pertama dan terakhir, garis, dan juga membalik urutan bit dalam byte yang membentuk array (bit paling tidak signifikan akan sesuai dengan titik bawah).
Karena saya sudah melukis sepuluh digit untuk kasus sebelumnya, untuk tugas terakhir itu tetap memperkenalkan prosedur pembalikan program:
byte reverse(byte x) { byte result=0,i; for(i=0;i<8;i++) { if (x & (1 << i)) { result |= 1 << (7-i); } } return result; }
Anda dapat mengubah urutan koordinat horizontal dan garis vertikal dengan membuat perubahan pada fungsi setGraphicCursor:
void setGraphicCursor( uint8_t x, uint8_t y ){ if( 0 <= x && x <= 99 ){ lcd.command(LCD_SETDDRAMADDR | (99-x)); } if( 0 <= y && y <= 1 ){ lcd.command(LCD_SETCGRAMADDR | (1-y)); } }
Fungsi output array setiap digit tetap sama, hanya sedikit pembalikan ditambahkan:
void draw2 (byte x/* */) // 2 { for (byte i = x; i<x+10; i++){ setGraphicCursor(i, 0); byte b=reverse(Data2[0][ix]); lcd.write(b); setGraphicCursor(i, 1); b=reverse(Data2[1][ix]); lcd.write(b);} }
Sketsa lengkap dari output arloji GraphicOLED_DC1307_100x16 dapat diunduh
dari sini , dan hasil untuk tampilan WEG010016AL ditampilkan dalam foto:

Tetapi dalam foto ini font dari tipe yang berbeda (16x16) pada layar WEG010016CG (tampilan juga terbalik):

Jika Anda membuat ulang font dengan mengubah urutan bit secara manual, maka tidak perlu melakukan sebaliknya dan program akan berjalan lebih cepat (walaupun tidak ada keterlambatan yang terlihat di mata). Tetapi prosedur membalik bit yang diberikan berguna dalam hal apa pun - untuk menampilkan berbagai gambar. Misalnya, dari satu panah yang menunjuk ke atas dan ke kanan, Anda secara terprogram dapat memperoleh empat arah sekaligus.
Menggambar panahGambar dan kode panah (koordinat dan bit dalam tabel terbalik sesuai dengan posisi konektor yang lebih rendah untuk tampilan WEG010016AL, lihat di atas):

const byte DataATR[2][8]={{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, {0x01,0x02,0x04,0x28,0x30,0x78,0x60,0x80}};
Fungsi untuk output panah multi arah:
. . . . . void drawSW (byte x) // ( ) { for (byte i = x; i<x+8; i++){ setGraphicCursor(i, 0); lcd.write(DataATR[0][ix]); setGraphicCursor(i, 1); lcd.write(DataATR[1][ix]);} } void drawNW (byte x) // ( ) {// : for (byte i = x; i<x+8; i++){ setGraphicCursor(i, 0); byte b=reverse(DataATR[1][ix]); lcd.write(b); setGraphicCursor(i, 1); b=reverse(DataATR[0][ix]); lcd.write(b);} } void drawNE (byte x) // ( ) {// , for (byte i = x; i<x+8; i++){ setGraphicCursor(i, 0); byte b=reverse(DataATR[1][7-(ix)]); lcd.write(b); setGraphicCursor(i, 1); b=reverse(DataATR[0][7-(ix)]); lcd.write(b);} } void drawSE (byte x) // ( ) {// for (byte i = x; i<x+8; i++){ setGraphicCursor(i, 0); lcd.write(DataATR[0][7-(ix)]); setGraphicCursor(i, 1); lcd.write(DataATR[1][7-(ix)]);} } . . . . .
Foto di bawah ini menunjukkan hasil program kosong untuk menampilkan sensor kecepatan dan arah angin. Seperti yang Anda lihat, ternyata sangat mudah untuk mengimplementasikan font dengan ukuran berbeda dalam satu baris bersama dengan gambar:

Sebagai kesimpulan, saya akan menambahkan bahwa ini adalah perpustakaan yang sangat menarik untuk bekerja dengan WS0010 dalam mode grafis dan tekstual menggunakan SPI. Dalam teks, sebagian besar salinan Liquid Crystal (dan apa lagi yang bisa Anda pikirkan?), Dan dalam grafik itu memiliki fungsi menggambar primitif grafis, font bawaan (tebal, seperti milik saya, dan 5x7 biasa) dan banyak lagi.