
Di luar jendela sedang hujan, Desember ada di kalender. Waktu untuk liburan sudah dekat, dan oleh karena itu waktu untuk hadiah. Rekan Pavel menginginkan laptop baru untuk dirinya sendiri, dan pacar Masha menginginkan sebuah rumah di tepi laut. Dan terlepas dari gaji yang layak dari profesi tyzhprogrammer, kami tidak hidup di dunia dengan kemungkinan tak terbatas, yang berarti saya tidak bisa memberi orang-orang ini persis apa yang paling mereka inginkan (meskipun Pasha mungkin adalah Pavel terbaik saya, yang Aku tahu, tapi Masha baik-baik saja).
Di sinilah masalah "hadiah murah" muncul. Tidak ada gunanya memberikan hadiah mahal kepada semua orang, tetapi saya tidak ingin memberikan sekotak coklat, lilin atau patung lain yang tidak jelas. Jadi, Anda perlu menggabungkan bisnis dengan kesenangan - Saya suka melakukan sesuatu dengan tangan saya sendiri, dan hasilnya hebat sebagai hadiah. Ini adalah kisah tentang bagaimana saya sekali lagi berpura-pura menjadi insinyur dan membuat beberapa hadiah.
Penyimpangan kecil dari topik utama
Saya tidak bisa langsung pergi ke topik utama, jadi saya akan mulai dari jauh. Beberapa tahun yang lalu, game "The Witcher 3" dirilis. Teman saya menyarankan saya untuk bermain, dan secara umum saya sangat mengagumi permainannya. Lalu saya memutuskan apa yang harus dilakukan dan memberinya sesuatu yang terkait dengan permainan ... saya tidak akan terlalu jauh ke dalam deskripsi permainan (Google akan membantu semua orang) atau mengatakan bahwa tidak banyak hal muncul di pikiran saya untuk kata kunci "The Witcher, Engineer, Gift."
Karakter utama dari permainan ini memiliki seekor kuda bernama "Roach" (dalam akting suara Rusia), pahlawan dari waktu ke waktu mendorongnya dengan ungkapan "Move, Roach". Saya memutuskan untuk membuat mainan mekanis dengan tema "mengaduk kecoak".
Tentu saja, hadiah itu dianggap sebagai hal yang sama sekali tidak berguna, bodoh, tetapi lucu, jadi rencananya adalah sebagai berikut:
- Ada kotak yang menyembunyikan mekanisme itu sendiri.
- Mekanismenya adalah poros, berputar dimana kuda itu bergerak.
- "Kegigihan" maksimum dari gerakan kuda ini disambut baik. Awalnya, ia bahkan berpikir bahwa kuda itu harus bergerak seperti ikan, dan tidak seperti kuda (setelah semua, kecoak), tetapi hasilnya adalah "sesuatu di antara".
- Semua ini akan dilakukan dari kayu lapis, yang menurut gambar dapat dipotong sesuai pesanan dengan laser.
Kerugian utama dari pemilihan material dan fakta bahwa pemotongan akan dilakukan sesuai pesanan adalah kenyataan bahwa saya kehilangan kesempatan untuk membuat prototipe, yang berarti bahwa semua masalah tangan yang bengkok dan ketidakpatuhan terhadap aturan "tujuh kali pengukuran" membuat diri mereka merasa cukup cepat:

Meskipun pada akhirnya, fakta bahwa banyak detail dari mekanisme serangan balik karena celah terlalu besar membantu untuk mengimbangi fakta bahwa saya menghubungkan bagian-bagian dan poros cukup bengkok. Di sini, seperti yang mereka katakan, "minus minus memberi plus" dan mekanisme secara keseluruhan bekerja, seperti yang dimaksudkan:

Setelah hanya ada sedikit lukisan dan hasilnya adalah kotak seperti itu:

Kemudian seseorang akan mengatakan bahwa itu perlu untuk membuat kotak transparan sehingga memungkinkan untuk mengamati pekerjaan bagian dalam, tetapi pada kenyataannya saya awalnya menduga bahwa saya tidak dapat mengumpulkan seluruh mekanisme dan kotak begitu bersih dan rapi dari dalam sehingga tidak ada salahnya lihat melalui dinding transparan kotak. Oleh karena itu, kotak buram adalah ukuran yang diperlukan.
Yang tersisa hanya mengemasnya, mengikat busur pada sebuah kotak dan hadiah sudah siap:

Tetapi agar tidak mengecewakan anak batin, yang ingin merasa seperti seorang insinyur dalam situasi di mana sebenarnya saya menempelkan beberapa potong kayu lapis, saya memutuskan untuk membuat "gambar". Maafkan saya semua yang mengerti sesuatu dalam gambar teknis, karena Saya mengerti bahwa ini lebih merupakan parodi dari gambar daripada gambar yang nyata, tetapi menurut saya, dia menambahkan nilai pada mainan sederhana:

Hari ini aku ...
Terkadang nasib bermain dengan kita dan entah bagaimana mengisyaratkan bahwa sesuatu akan segera terjadi. Kisah salah satu perangkat saya dimulai persis sama. Saya memesan beberapa barang elektronik kecil bernilai sekitar $ 5, yang, seperti biasa, menghabiskan waktu satu bulan di jalan, setelah itu saya menerima SMS bahwa paket itu menunggu saya di kantor pos setempat. Kotak itu ternyata jauh lebih besar dari yang saya harapkan dan segera menimbulkan keraguan tentang isinya. Keraguan dikonfirmasi - di dalam, selain hal-hal kecil yang saya pesan, ada juga layar e-ink tiga warna dengan diagonal 4,2 inci. Saya menghubungi penjual, dia mengkonfirmasi bahwa dia telah mengacaukan sesuatu ketika berkemas, tetapi mengatakan bahwa saya dapat menganggap ini hadiah dan menggunakannya sesuai keinginan saya.
Fate mengisyaratkan kepada saya bahwa saatnya telah tiba untuk memulai proyek baru dan proyek ini akan menjadi sesuatu dengan tampilan e-ink. Setelah secara singkat membiasakan diri dengan spesifikasi perangkat dan menghubungkan layar ke controller, saya memastikan bahwa spesifikasi tidak berbohong kepada saya tentang waktu pembaruan. Layar telah diperbarui selama lebih dari 10 detik, berkedip dan mencoba membuat saya kejang epilepsi:

(Saya tidak punya foto awal untuk menghubungkan layar, jadi di sini perangkat sudah memiliki tampilan yang lebih bermakna)
Menjadi jelas bahwa Anda memerlukan perangkat sederhana yang tidak memerlukan animasi yang rumit (dan animasi pada umumnya). Dan kemudian saya menemukan kalender suasana hati:

Kalender mood adalah serangkaian gambar sederhana dan tanda tangan ironis bagi mereka. Saya memutuskan bahwa saya akan membuat kalender (yang sebenarnya bukan kalender sama sekali) dengan nama "Hari ini saya" ... Ini akan menjadi perangkat sederhana yang setiap hari menampilkan beberapa gambar yang mencirikan "keadaan pikiran" hari ini dan deskripsi tentangnya. Selain itu, kalender bisa memiliki beberapa fungsi lain juga, tetapi kalender utama akan tepatnya "kalender" - gambar sendiri untuk setiap hari.
Modul kertas elektronik memungkinkan untuk menampilkan tiga warna (hitam, merah dan putih), yang harus dikirim ke modul, seperti dua gambar - hitam dan putih dan merah dan putih. Bahkan, akan lebih tepat untuk mengatakan bahwa layar hanya mengharapkan bitmap monokrom, di mana setiap bit menentukan warna satu piksel (saya tidak yakin bahwa istilah ini berlaku untuk kertas elektronik, tapi saya harap idenya jelas). Bitmap terpisah dapat diatur untuk saluran hitam atau merah. Dengan demikian, ada satu set byte di mana setiap bit yang diatur ke 1 akan sesuai dengan piksel warna, dan semua bit yang tetap 0 akan menjadi piksel putih pada layar. Resolusi layar adalah 400 x 300 piksel, mis. untuk gambar hitam putih, diperlukan 15.000 byte (8 piksel dikodekan dalam satu byte). Untuk tiga warna, ini akan membutuhkan 30.000 byte, jika Anda tidak mencoba mengemas gambar dengan lebih kompak. Dari sudut pandang implementasi, pencipta layar dapat dengan mudah memilih dua bit per piksel dan menyimpan keadaan sebenarnya (di mana merah, di mana hitam, dan di mana putih), tetapi ini akan membutuhkan 30.000 byte yang sama, tetapi bahkan untuk gambar monokrom akan membutuhkan transfer 30.000 byte.
Seperti dalam "kerajinan" saya yang lain, saya mulai menciptakan tugas untuk diri saya sendiri sehingga semuanya tidak akan berubah menjadi "pasang kabel dan unduh perpustakaan". Bahkan jika kita mempertimbangkan kemampuan untuk menerapkan semacam algoritma kompresi gambar pada sisi pengontrol, menjadi jelas bahwa tanpa penyimpanan eksternal untuk file gambar, pengontrol akan sangat tertekan. Diputuskan untuk mengambil kartu SD dan menulis pembungkus kode sederhana untuk bekerja dengan FAT32. Tentu saja, akan mungkin dilakukan tanpa sistem file dan menulis data ke kartu memori secara langsung, tetapi bagi saya tampaknya kurang nyaman untuk menambahkan file baru, dan menarik bagi saya untuk mengimplementasikan operasi dasar untuk bekerja dengan FAT32 dengan tangan saya sendiri.
Penting untuk mengklarifikasi bahwa saya memiliki kebiasaan menulis sendiri (Anda tidak harus memberi tahu saya bahwa ada lautan perpustakaan, saya tahu tentang hal itu dan dengan Google) ketika saya melakukan hal-hal seperti itu, tetapi karena Sebelumnya saya tidak merasa senang bekerja dengan FAT32 di level rendah, itu adalah proses yang agak menghibur.
Saya tidak akan membahas detail bekerja dengan FAT32 dan kartu SD secara keseluruhan, seperti Internet penuh dengan artikel tentang topik ini (dan saya tidak ingin mengubah cerita saya menjadi menceritakan kembali spesifikasi), tetapi saya akan berbicara tentang beberapa hal yang perlu diterapkan. Penting untuk mengimplementasikan tidak hanya fungsi membaca dari file dan menulis ke file (saya memutuskan untuk menyimpan beberapa pengaturan dan menyatakan pada kartu SD yang sama, dan tidak di EEPROM), tetapi juga fungsi mencari file dalam sistem file jika Anda perlu bekerja dengan dengan cara yang biasa.
Semua data pada kartu memori dibagi menjadi cluster (unit utama yang dapat dialamatkan dalam sistem file FAT32), dan cluster sudah dibagi menjadi beberapa sektor. Untuk membaca file βhabr.txtβ dari kartu SD di FAT32, Anda perlu:
- Inisialisasi kartu memori.
- Baca sektor di alamat nol dan periksa apakah sistem file FAT32 memiliki header tertentu (Anda dapat melewati langkah ini jika kami percaya pada keberuntungan).
- Baca sektor ini di alamat nol dan dapatkan βLogical Block Addressingβ (LBA).
- Baca sektor di alamat yang diterima (LBA) dan dapatkan data yang diperlukan dari itu (cluster mana yang merupakan root - direktori root, berapa banyak sektor dalam cluster, dll.).
- Baca "Root Directory" cluster (pada kenyataannya, membaca dilakukan oleh sektor, Anda hanya perlu membaca sektor sebanyak ada sektor dalam cluster) dengan nomornya. Ini memiliki formula sendiri untuk mengubah nomor seri cluster menjadi alamat fisik. Informasi file disimpan di sini, jadi kami membaca data untuk mencari file yang diinginkan. Ada satu hal lagi tentang nama file: nama bisa pendek atau panjang, tergantung pada ini, data disimpan di satu tempat (dalam struktur yang sama) atau dalam catatan tambahan, yang juga harus dibaca secara terpisah. Ketika file dengan nama yang diinginkan ditemukan, kami mendapatkan cluster di mana awalnya terletak (atau mungkin seluruh file jika cocok dengan ukuran cluster), serta ukuran file. Jika file tidak ditemukan di cluster ini, maka kami mencari cluster berikutnya dan ulangi proses pencarian file.
- Baca cluster di alamat yang ditemukan. Dan terus membaca cluster lebih lanjut dan mencari cluster berikutnya sampai semua data telah dibaca.
Tampak bagi saya bahwa lebih mudah untuk memberi tahu prinsip sistem file kepada mereka yang telah menerapkan daftar tertaut setidaknya sekali, karena sebenarnya, sistem file FAT32 adalah seperangkat blok data dan sejenis tabel yang mengatakan di mana harus mencari blok data berikutnya. Membaca data apa pun dari FAT32 adalah proses di mana kami membaca data, mencari alamat blok berikutnya, membaca data, mencari alamat blok berikutnya, dll.
Saya tidak menerapkan semua skenario yang mungkin dan menyederhanakan beberapa hal:
- Semua file pada akar kartu memori dan penelusuran direktori tidak digunakan.
- Semua file memiliki nama pendek.
- Pengontrol saat startup membaca daftar file dan menyimpannya dalam memori agar tidak mencari setiap file lagi.
- Jumlah maksimum file dibatasi oleh konstanta (dan sebenarnya saya hanya menggambar beberapa lusin gambar).
Singkatnya, semua hal di atas adalah alasan yang meyakinkan untuk mengambil perpustakaan yang sudah jadi dan tidak menghabiskan banyak waktu membaca dokumentasi, pengembangan dan debugging. Saya akan menyarankan diri saya untuk menerapkan hal-hal seperti itu hanya untuk tujuan pendidikan atau "untuk bersenang-senang".
Layar juga memberlakukan beberapa batasan, seperti gambar apa pun yang ditampilkan dengan cara ini:
- Kami bangun dan menginisialisasi layar (untuk memperpanjang umurnya dan menghemat energi, tampilan pada dasarnya tidur).
- Kami membuka saluran yang diperlukan (misalnya, hitam).
- Kami meneruskan 15000 byte gambar.
- Kami membuka saluran yang diperlukan (misalnya, merah).
- Kami meneruskan 15000 byte gambar.
- Kami memberi tahu tampilan untuk mengambil data dari buffer.
- Kami menunggu sampai layar selesai menggambar.
- Kami memberitahu layar untuk tidur.
Untuk gambar monokrom, Anda dapat melewati langkah 4 dan 5. Untuk gambar tiga warna, urutan transmisi gambar hitam putih dan merah putih tidak penting, karena merah selalu dicat hitam, hitam hanya di atas putih, dan hanya piksel tetap putih, yang putih dan hitam dan putih dan merah dan putih.
Untuk kesederhanaan (agar tidak menambah jumlah total file), saya memutuskan untuk menyimpan gambar hitam putih dan merah putih sebagai satu file, di mana gambar hitam putih segera diikuti oleh merah putih:

Hasil membandingkan gambar-gambar ini adalah sesuatu seperti ini (menurut saya masing-masing dari kita setidaknya sekali dalam hidup kita merasa seperti rusa dengan tanduk - kaki):

Bahkan, kedua gambar itu diikuti oleh gambar lain yang berisi deskripsi keadaan (dengan mengklik tombol, Anda bisa mendapatkan deskripsi yang cocok dengan gambar yang ditampilkan hari ini).
Karena keterbatasan memori pengontrol, data dari kartu memori tidak pernah sepenuhnya dibaca ke dalam memori pengontrol. Gambar dari kartu memori dibaca dalam fragmen yang ditentukan oleh ukuran sektor (untuk kesederhanaan, kami menganggap bahwa ukuran ini selalu statis dan tidak dapat berubah dari kartu ke kartu) dan jatuh ke dalam proses pemrosesan data dari kartu. Dalam implementasi saya, fungsi membaca file sebagai input nomor cluster, ukuran file, dan panggilan balik untuk "ditarik" untuk setiap sektor membaca. Pendekatan ini memungkinkan kami untuk menggunakan beberapa fungsi pemrosesan file yang berbeda untuk membaca dan menampilkan gambar itu sendiri atau deskripsinya.
Jadi, logika berikut jatuh pada fungsi panggilan balik untuk membaca gambar dari kartu memori:
- Atur saluran yang diperlukan (saluran ditentukan secara acak) sebelum mengirim data ke tampilan.
- Melacak data yang dikirimkan untuk beralih saluran ketika pengiriman data untuk saluran sebelumnya selesai.
- Kirim data yang diterima dari kartu.
- Tentukan bahwa data yang diperlukan telah dikirim dan sisa data (gambar dengan deskripsi) dapat diabaikan.
Itu rumit oleh kenyataan bahwa saya memutuskan untuk memasukkan gambar yang berisi lebih banyak data daripada yang seharusnya ditampilkan di layar. Yaitu ada beberapa gambar, yang merupakan latar belakang dan selalu statis dan sesuai dengan ukuran layar, dan ada gambar yang jauh lebih besar dari mana Anda perlu mengambil area acak (ukuran layar) dan tampilan.
Gambar seperti itu memberlakukan persyaratan tambahan pada pawang - perlu untuk menghitung berapa byte dari garis layar saat ini ditransfer, berapa banyak lagi yang perlu ditambahkan pada panggilan berikutnya (jika garis jatuh di perbatasan ukuran sektor) dan berapa banyak yang harus dilewati.
Secara visual, situasi ini dapat ditampilkan seperti ini:

Ada buffer tertentu di mana ada "jendela" dari ukuran yang diperlukan (bagian hijau) dan Anda hanya perlu membaca data dari jendela ini, membaca data dari buffer dalam fragmen N byte. Dimungkinkan untuk memvisualisasikan proses membaca seperti ini:

Secara umum, untuk menambahkan logika bekerja dengan layar ke dalam fungsi yang selalu menerima buffer 512-byte dan yang harus menentukan mana dari 512 byte ini yang diperlukan (jika ada sesuatu yang diperlukan sama sekali) ternyata bukan tugas yang mudah untuk diselesaikan "Di dahi". Lebih tepatnya, tugas itu tidak begitu rumit sebagai non-standar dibandingkan dengan solusi sehari-hari, oleh karena itu, sangat mengejutkan, itu sangat menarik untuk menyelesaikannya. Bagi saya itu seperti "tugas olimpiade", di mana perlu untuk menghitung jumlah listrik yang diperlukan untuk berkontraksi otot untuk mentransfer air dari satu ember ke ember lain dengan dua sendok (satu sendok di masing-masing tangan).
Untuk lebih memahami apa kesulitannya di sini, saya akan menambahkan animasi lain di sini, hanya "dalam hal" isi cluster, dan bukan seluruh file (semua informasi lain perlu disimpan secara terpisah):

Seperti yang direncanakan, kalender harus menampilkan gambar baru setiap hari, mis. itu harus dapat memonitor waktu (bahkan ketika dimatikan), yang berarti bahwa modul jam waktu nyata (RTC) juga diperlukan. Dan terlepas dari kenyataan bahwa controller saya memiliki jam real-time built-in, hampir tidak mungkin untuk mengambil baterai untuk itu, karena kontak tidak terhubung ke papan. Saya memutuskan untuk tidak memperkosa kaki pengontrol dalam upaya menyoldernya dan mengambil RTC Cina eksternal. Bekerja dengan RTC seharusnya sangat sederhana:
- Ketika dihidupkan, dapatkan waktu dari RTC Cina.
- Atur waktu dalam RTC internal.
- Gunakan RTC internal untuk menghitung waktu dan lupakan orang Cina sampai penutupan berikutnya.
Tapi di sini, semuanya ternyata tidak begitu sederhana, karena RTC internal dari pengontrol bekerja dengan waktu dalam format yang biasa (timestamp UNIX), dan teman Cina-nya menggunakan Binary Coded Decimal (BCD). Sebelum ini, saya tidak menemukan format ini dan sangat terkejut bahwa bahkan modul modern untuk Arduino menggunakannya. Inti dari format ini cukup sederhana - ada satu byte, yang, misalnya, menyimpan jumlah detik. Empat bit orde tinggi menyimpan puluhan, dan empat unit orde rendah menyimpan unit. Ternyata representasi heksadesimal dari byte ini sendiri berisi waktu yang dapat dibaca manusia - byte 0x49 sesuai dengan 49 detik (walaupun dalam sistem desimal nilai ini sesuai dengan 72).
Seperti yang saya pahami, itu hanya terjadi secara historis sehingga lebih mudah untuk menggunakan RTC secara langsung dengan pembuat enkode layar untuk membuat jam, tetapi saya harus mengubah stempel waktu BDC ke UNIX dengan pena.
Selain tampilan, modul jam waktu nyata, kartu memori, dan sistem file untuk itu, perlu untuk membungkus semua kelenjar ini ke dalam case, yang juga harus diproduksi, mis. "Gambar". Anda dapat membaca lebih detail tentang semua rasa sakit yang saya temui dalam publikasi terakhir saya, semuanya persis sama di sini:

(Saya tidak merencanakan produksi massal, semua detail di sekitar adalah hasil pengukuran yang salah atau solusi yang dipikirkan dengan buruk)
Akibatnya, kasing dan detail yang diperlukan ditarik (tidak ada sampul depan pada gambar):

(, - - ):

( ) :

. , .
( ):

, β :

, , :

!
-, : β ?! 100500 , !β. , , β ( - ), , , , .
, , , .
3 . , , .
, , - . , , , , , - .
, , . β--β, βMP3 Music Player Module for Arduinoβ, Arduino Nano, , mp3 .
, , , , , , / , . ββ , .
3 , . :
- , .
- ββ (, , , ).
( ):

, , .. , ( : playSound(rand() & 3);).
. ββ ( , ), USB , β β:

?
, , . 3 :

β . , :

!
, :
- .
- 3 2 , ~0.4.
- β .
- 3 ( ).
- .
β¦ :

:

ββ:

?
β - , - .β , , -. ββ, , , FAT32, BCD , RTC.
, - ( ) : β , , !β - .
, . , . , , __!