51 マイクロコントローラーを使用した LED 呼吸ライトの実装

Jun 11, 2026 伝言を残す

[導入]


マイクロコントローラー技術は、現代の産業オートメーション、エレクトロニクス、電気工学、およびモノのインターネット (IoT) において不可欠な主流技術です。私たちの生活がますますスマートになるにつれて、マイクロコントローラー技術は、スマート炊飯器やスマートスピーカーなど、私たちの日常生活のほぼあらゆる側面に浸透しています。


これを念頭に置いて、「51 マイクロコントローラーの再学習」シリーズの記事は、初心者がマイクロコントローラー テクノロジを始めるのに役立つことを目的としています。まず、-1 つの LED を点灯する-という最も単純なタスクから始めて、ボタン コントロール、LCD1602 ディスプレイ、DS18B20 および DS1302 温度センサー、2 つのマイクロコントローラー間の通信などのモジュールの実装に徐々に進みます。 UART、I²C、SPI などのハードウェア通信プロトコルについても説明します。これらの概念を C プログラミング手法と組み合わせることで、実際のエンジニアリング プロジェクトを使用してプログラミング アプローチを説明します。これにより、C ポインタと構造を柔軟に適用してモジュール型プログラミングを実現できるようになります。{10}


さて、本題に戻りましょう。51 マイクロコントローラーを使用して LED を制御し、呼吸する光の効果を作成します。

 

【ブリージングライトの仕組み】


まず、呼吸光エフェクトがどのように機能するかを見てみましょう。
呼吸ライトは徐々に明るくなり、徐々に暗くなり、呼吸と同じようにこのサイクルを繰り返します。しかし、マイクロコントローラーのピンは 1 (オン) または 0 (オフ) のいずれかしか出力できないため、段階的な遷移効果はどのように達成できるのでしょうか?
これは私たちの目に視覚が持続するためです。私たちが何かを見るとき、私たちの目に形成されるイメージは 0.04 秒間持続します (この数字はオンラインで見つかりました)。
0.04 秒に基づいて計算すると、40 ミリ秒に相当します。したがって、LED が 20 ms ずつオンとオフを繰り返すと、人間の目には常に点灯しているように見えます。

图片

LED が 20 ミリ秒間点灯し、20 ミリ秒間消灯する効果は、常に点灯し続けることと同じですか?

 

ははは、確かに違いますね。ライトが 20 ミリ秒ごとにオンとオフを繰り返す場合、目に見える効果は、継続的に点灯し続ける場合よりも薄暗くなります。連続点灯するライトの明るさを 100% とすると、20 ミリ秒ごとに点灯と消灯を繰り返すライトの明るさは 50% になります。これに基づいて、LED の明るさを調整できます。

图片

 

この時点で、LED の明るさを調整できます (40ms 周期内の高レベルの継続時間を設定することによって)。これは、よく知られている輝度制御の PWM (パルス幅変調) 法の背後にある原理です。-、ハイ レベルの期間を設定することは、デューティ サイクル (つまり、ハイ レベルの期間を合計サイクルで割った値: 20/40=50%) を調整することと同じです。


ここで、最も重要な要素はこのデューティサイクルです。たとえば、周期が 20 ms で、LED が 10 ms オンと 10 ms オフを繰り返す場合、知覚される明るさは依然として 50% です (つまり、デューティ サイクルは 10/20=50%)。

次に、これがプログラムでどのように実装されるかを見てみましょう。

 

【プログラムの実施】


LEDを点灯する
まずは LED を点灯させてから、徐々に光の呼吸効果を実装していきます。使用するハードウェアは次のとおりです。

開発ボード ZeroOne マイクロコントローラー トレーニング開発ボード
マイコンモデル STC89C52
LEDインターフェース ピン P4^4
图片

 

回路図から、LED がマイクロコントローラーのピン P4^4 に接続されていることがわかります。マイクロコントローラーが 1 を出力すると、LED が点灯します。 0 を出力すると LED が消灯します。したがって、以下に示すように、LED を点灯するプログラムは非常に簡単です。

info-299-230

 

 

LED を点灯するプログラムは非常に簡単です。誰もがその方法を知っていると思います。
 

LEDの明るさを調整する


次に、次のように明るさを調整 (つまり、デューティ サイクルを調整) できる関数を実装します。

info-400-538


 

静的変数 `duty_cycle` を定義してデューティ サイクルを保存します。 「flag」が 1 の場合、デューティ サイクルは 255 まで徐々に増加し、その後「flag」を 0 に設定し、「duty_cycle」は 255 から 0 まで徐々に減少します。このサイクルを繰り返します。
はは、この時点で、呼吸ライトがすでに機能していると思うかもしれませんが、そうではありません。私の言うことが信じられない場合は、上記のコードを自分で試してみてください。

では、問題は一体どこにあるのでしょうか?


問題は、明るさ設定関数 `set_led_luminance()` を直接呼び出していることにあります。{0}この関数は 1 サイクルを完了するのに 40 ミリ秒かかります。つまり、この 40 ミリ秒の間はデューティ サイクルを変更できません。そうしないと、明るさ調整が機能しません。 「breath_led」関数をもう一度見てみましょう。 `set_led_luminance()` を呼び出してデューティ サイクルを設定するたびに、40 ミリ秒を待たずにすぐに `duty_cycle` 値を変更します。


この時点で、40 ミリ秒が経過した後に「duty_cycle」値を更新するソフトウェア タイマーを追加する必要があります。変更したプログラムは次のとおりです。

info-495-656

 

 

注: タイマーの継続時間は 40 ミリ秒より大きくなければなりません (つまり、`s_breathCounter` の値は 255 より大きくなければなりません) が、サイクルの倍数に設定するのが最善です。たとえば、サイクルが 255 (つまり、0 ~ 255 の 256 個の値) の場合、その値の 2 倍、256 * 2 - 1=511 (つまり、0 ~ 511 の 512 個の値) に設定できます。
これで、-呼吸用ライトが完成しました。それは簡単ではありませんか? (* ̄︶ ̄)

 

続いて今日のおまけコーナーです。

呼吸するような光の効果は得られましたが、コードは十分に簡潔でもエレガントでもありません。{0}多くの if ステートメントと else ステートメントが使用されています。さらに単純化できるかどうか見てみましょう。

まず、下の図に示すように、set_led_luminance() 関数のこのセクションを単純化してみましょう。
 

图片

 

これを単純化する前に、C に関する簡単なヒント、つまりビットごとの AND 演算について説明しましょう。

info-600-117

 

このことから、1 であっても 0 であっても、0 とビットごとの AND 演算を実行すると結果は 0 になることがわかります。

1 であっても 0 であっても、1 とビット単位の AND 演算を実行すると、元の値が得られます。

便宜上、16 進表記 (接頭辞「0x」) を使用します。たとえば、0xff は 10 進数の 255 に対応します。したがって、

 

0xff 以下の数値と 0xff の AND 演算を行うと、以下に示すように、結果は数値そのものになります。

info-534-63

 

 

0xff より大きい数値と 0xff の間でビット単位の AND 演算を実行するとどうなりますか?

info-551-63

結果は、この数値を (0xff + 1) で割ったときの余りになります (つまり、結果はまだ 0 と 0xff の間にあります)。
このビットごとの AND 演算を使用すると、上記のコードは次のように簡略化できます。

info-550-64

 

 

こうすることで、s_Counter の値は常に 0x00 ~ 0xff の範囲内になります。
同様に、上記の Breath_led 関数のソフトウェア タイマーも次のように簡略化できます。

info-389-353

3行目の0x1ffは10進数で511です。 s_breathCounter の値が (0x1ff+1) または 512 の場合、条件は true です。512 & 0x1ff=0. であるため、その前の感嘆符はビット単位の NOT 演算を示します (正確には、`s_breathCounter` の値が 512 の倍数である場合に条件が満たされます。これにより、リセットする必要がなくなります) 「s_breathCounter」。この説明が明確であることを願っています-よく考えてください)。条件が満たされると、デューティ サイクルが増加または減少し始めます。


しかし、デューティサイクルの範囲は 0 ~ 255 ではないでしょうか? 5 行目も 0x1ff (511) になるのはなぜですか?心配しないでください。-8 行目を見てください。再び 0xff を減算するので、デューティ サイクルの範囲は 0 ~ 255 のままです。


行 7 ~ 10 は、「duty_cycle > (0xff)」、つまり 256 ~ 511 の場合、0xff を減算することは 1 から 255 に増加することと同等であるため、明るさが徐々に増加することを意味します。


デューティサイクルのとき<= 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.


はは、簡素化は終わったと思いましたか?

 

いいえ、いいえ、いいえ

実際には、7 行目から 10 行目はさらに簡略化できます。ここで絶対値関数が役に立ちます。

何?なぜ絶対値関数を使用するのでしょうか?

 

10 行目を見てください: 0xff -duty_cycle は、duty_cycle - 0xff に相当し、絶対値を取ります。さて、簡略化されたコードは次のとおりです。

set_led_luminance(ABS(デューティ サイクル - (0xff)));

 

 

絶対値をとるマクロ関数は以下の通りです。

#define ABS(N) ((N) < 0 ? -(N) : (N))

 

最後に、簡略化したコード全体を以下に示します。

 

info-562-684

どう思いますか?単純なことではありませんか? (* ̄︶ ̄)

お問い合わせを送る

whatsapp

電話

電子メール

引き合い