[Perkenalan]
Teknologi mikrokontroler adalah teknologi arus utama yang sangat diperlukan dalam otomasi industri modern, elektronik, teknik elektro, dan Internet of Things (IoT). Seiring dengan semakin canggihnya kehidupan kita, teknologi mikrokontroler telah merambah hampir setiap aspek kehidupan kita sehari-hari, seperti pada penanak nasi pintar, speaker pintar, dan banyak lagi.
Dengan mengingat hal ini, rangkaian artikel "Mempelajari Kembali 51 Mikrokontroler" bertujuan untuk membantu pemula memulai dengan teknologi mikrokontroler. Kita akan mulai dengan tugas paling sederhana-menghidupkan satu LED-dan secara bertahap melanjutkan ke penerapan modul seperti kontrol tombol, layar LCD1602, sensor suhu DS18B20 dan DS1302, dan komunikasi antara dua mikrokontroler. Kami juga akan membahas protokol komunikasi perangkat keras seperti UART, I²C, dan SPI. Dengan menggabungkan konsep-konsep ini dengan teknik pemrograman C, kami akan menggunakan proyek{10}rekayasa dunia nyata untuk mengilustrasikan pendekatan pemrograman, sehingga Anda dapat secara fleksibel menerapkan pointer dan struktur C untuk mencapai pemrograman modular.
Sekarang, mari kembali ke topik utama: menggunakan mikrokontroler 51 untuk mengontrol LED dan menciptakan efek cahaya bernapas.
(Cara Kerja Lampu Pernapasan)
Pertama-tama mari kita lihat cara kerja efek cahaya pernapasan.
Cahaya pernapasan berangsur-angsur menjadi terang dan kemudian meredup secara bertahap, mengulangi siklus ini dengan cara yang menyerupai pernapasan. Namun, karena pin mikrokontroler hanya dapat menghasilkan output 1 (hidup) atau 0 (mati), bagaimana efek transisi bertahap dapat dicapai?
Hal ini disebabkan oleh masih adanya penglihatan pada mata kita. Saat kita melihat sesuatu, bayangan yang dibentuk oleh mata kita bertahan selama 0,04 detik (angka ini ditemukan online).
Jika kita menghitung berdasarkan 0,04 detik, itu sama dengan 40 ms. Oleh karena itu, ketika LED hidup dan mati masing-masing selama 20 ms, bagi mata manusia tampak seolah-olah menyala terus-menerus.

Apakah efek LED yang menyala selama 20 ms dan mati selama 20 ms sama dengan efek menyalakannya sepanjang waktu?
Haha, pasti berbeda. Saat lampu menyala dan mati secara bergantian setiap 20 milidetik, efek yang kita lihat lebih redup dibandingkan saat lampu terus menyala. Jika kita asumsikan kecerahan lampu yang menyala terus menerus adalah 100%, maka kecerahan lampu yang menyala dan mati secara bergantian setiap 20 milidetik adalah 50%. Berdasarkan ini, kita dapat mengatur kecerahan LED.

Pada titik ini, kita dapat mengatur kecerahan LED (dengan mengatur durasi level tinggi dalam siklus 40ms). Ini adalah prinsip di balik metode kontrol kecerahan PWM (Pulse Wide Modulation) yang terkenal, dan mengatur durasi tingkat tinggi setara dengan menyesuaikan siklus kerja (yaitu, durasi tingkat tinggi dibagi total siklus: 20/40=50%).
Di sini, faktor terpenting adalah siklus kerja ini. Misalnya, jika periodenya adalah 20 mdtk, dengan LED bergantian antara 10 mdtk menyala dan 10 mdtk mati, kecerahan yang dirasakan masih 50% (yaitu, siklus kerjanya adalah 10/20=50%).
Selanjutnya, mari kita lihat bagaimana hal ini diterapkan dalam program.
[Implementasi Program]
Menghidupkan LED
Pertama, mari kita mulai dengan menyalakan LED, lalu secara bertahap kita akan menerapkan efek cahaya bernapas. Perangkat keras yang akan kami gunakan adalah sebagai berikut:
| Dewan Pengembangan | Badan Pengembangan Pelatihan Mikrokontroler ZeroOne |
|---|---|
| Model Mikrokontroler | STC89C52 |
| Antarmuka LED | Sematkan P4^4 |

Dari skema terlihat bahwa LED dihubungkan ke pin P4^4 mikrokontroler. Ketika mikrokontroler mengeluarkan angka 1, LED menyala; ketika menghasilkan 0, LED mati. Oleh karena itu, program untuk menyalakan LED cukup sederhana, seperti gambar di bawah ini:

Program untuk menyalakan LED cukup sederhana; Saya yakin semua orang tahu bagaimana melakukannya.
Menyesuaikan Kecerahan LED
Selanjutnya, kita akan menerapkan fungsi yang memungkinkan kita menyesuaikan kecerahan (yaitu menyesuaikan siklus kerja), sebagai berikut:

Tentukan variabel statis `duty_cycle` untuk menyimpan siklus tugas. Ketika `flag` adalah 1, siklus kerja secara bertahap meningkat menjadi 255, kemudian mengatur `flag` menjadi 0, dan `duty_cycle` secara bertahap menurun dari 255 menjadi 0. Ulangi siklus ini.
Haha, saat ini Anda mungkin mengira lampu pernapasan sudah berfungsi, padahal sebenarnya tidak. Jika tidak percaya, coba sendiri kode di atas.
Jadi di mana sebenarnya masalahnya?
Masalahnya terletak pada panggilan langsung kita ke fungsi-pengaturan kecerahan `set_led_luminance()`. Fungsi ini membutuhkan waktu 40 ms untuk menyelesaikan satu siklus, yang berarti siklus kerja tidak dapat diubah selama 40 ms tersebut; jika tidak, penyesuaian kecerahan tidak akan berfungsi. Mari kita lihat lagi fungsi `breath_led`. Setelah setiap panggilan ke `set_led_luminance()` untuk menyetel siklus kerja, nilai `duty_cycle` akan segera berubah tanpa menunggu selama 40 ms.
Pada titik ini, kita perlu menambahkan pengatur waktu perangkat lunak untuk memperbarui nilai `duty_cycle` setelah 40 ms berlalu. Program yang dimodifikasi adalah sebagai berikut:

Catatan: Durasi pengatur waktu hanya perlu lebih besar dari 40 ms (artinya nilai `s_breathCounter` harus lebih besar dari 255), namun sebaiknya atur ke kelipatan siklus. Misalnya, jika siklus kita adalah 255 (yaitu, 256 nilai dari 0 hingga 255), kita dapat menyetelnya menjadi dua kali lipat nilai tersebut: 256 * 2 - 1=511 (yaitu, 512 nilai dari 0 hingga 511).
Dan begitulah-lampu pernapasan kita sudah lengkap! Bukankah itu sederhana? (* ̄︶ ̄)
Selanjutnya adalah bagian bonus hari ini.
Meskipun kita telah mendapatkan efek ringan, kodenya tidak cukup ringkas atau elegan-kode ini menggunakan sekumpulan pernyataan if dan else. Mari kita lihat apakah kita bisa menyederhanakannya lebih lanjut.
Pertama, mari kita sederhanakan bagian fungsi set_led_luminance() ini, seperti yang ditunjukkan pada gambar di bawah.

Sebelum kita menyederhanakannya, mari kita bahas tip singkat tentang C: operasi AND bitwise.

Dari sini, kita tahu bahwa apakah itu 1 atau 0, melakukan operasi AND bitwise dengan 0 menghasilkan 0.
Baik itu 1 atau 0, melakukan operasi AND bitwise dengan 1 menghasilkan nilai asli.
Untuk kenyamanan, kami menggunakan notasi heksadesimal (diawali dengan "0x"); misalnya, 0xff sama dengan 255 dalam desimal. Karena itu,
Bila suatu bilangan yang kurang dari atau sama dengan 0xff di AND dengan 0xff maka hasilnya adalah bilangan itu sendiri, seperti gambar di bawah ini

Apa yang terjadi jika Anda melakukan operasi AND bitwise antara angka yang lebih besar dari 0xff dan 0xff?

Hasilnya adalah sisa bila bilangan tersebut dibagi (0xff + 1) (yaitu hasilnya masih antara 0 dan 0xff).
Dengan operasi AND bitwise ini, kode di atas dapat disederhanakan menjadi

Dengan cara ini, nilai s_Counter akan selalu berada dalam rentang 0x00 hingga 0xff.
Demikian pula software timer pada fungsi breath_led di atas juga dapat disederhanakan sebagai berikut:

Pada baris 3, 0x1ff adalah 511 dalam desimal. Kondisi ini benar ketika nilai s_breathCounter adalah (0x1ff+1), atau 512, karena 512 & 0x1ff=0. Tanda seru sebelum menunjukkan operasi NOT bitwise (tepatnya, kondisi terpenuhi ketika nilai `s_breathCounter` adalah kelipatan 512; ini menghilangkan kebutuhan untuk mengatur ulang `s_breathCounter`. Saya harap penjelasan ini jelas-tolong pikirkan baik-baik). Jika kondisi ini terpenuhi, siklus kerja mulai bertambah atau berkurang.
Tapi bukankah siklus kerjanya berkisar 0 hingga 255? Mengapa baris 5 juga menjadi 0x1ff (511)? Jangan khawatir-lihat baris 8. Kita kurangi lagi 0xff, sehingga rentang siklus kerja tetap 0 hingga 255.
Baris 7–10 berarti: Ketika `duty_cycle > (0xff)`, yaitu 256–511, mengurangi 0xff sama dengan meningkatkan dari 1 menjadi 255, sehingga kecerahannya meningkat secara bertahap.
Saat tugas_siklus<= 0xff, the duty_cycle increases from 0 to 255, while the set brightness is 255 - duty_cycle. This effectively decreases the brightness from 255 to 0, causing the light to gradually dim. This achieves the breathing light effect.
Haha, menurutmu penyederhanaan kita sudah selesai?
Tidak tidak tidak
Sebenarnya baris 7 sampai 10 bisa disederhanakan lebih jauh lagi. Di sinilah fungsi nilai absolut berguna.
Apa? Mengapa menggunakan fungsi nilai absolut?
Lihat baris 10: 0xff - duty_cycle setara dengan duty_cycle - 0xff lalu ambil nilai absolutnya. Oke, ini kode yang disederhanakan:
Fungsi makro untuk mengambil nilai absolut adalah sebagai berikut
Terakhir, saya telah menyertakan seluruh kode sederhana di bawah ini

Bagaimana menurutmu? Sederhana bukan? (* ̄︶ ̄)




