HOME > 技術談話 > PIC® microcontroller > LEDのPWM制御

はじめに キーワード LEDの輝度調整 プログラミング手法 ハードウェアによる制御方法 
サンプルプログラム(その1:点灯比率固定) サンプルプログラム(その2:制御周期固定) 
サンプルプログラム(その3:割り込み) サンプルプログラム(その4:ハードウェアPWM機能) 

おまけ(蛍風) サンプルプログラムの問題点と対応
(04/19) 


■はじめに

 LEDの制御手法としてスタティック制御を初級編で解説しました(1つの出力端子に1つのLEDを接続)。
 スタティック制御は数個のLEDを制御するには便利ですが、
  「LEDの数=出力端子の数」
なので、より多くのLEDを制御する場合は必要な数だけ出力端子を増やさなければなりません。

 そこで先人達はダイナミック制御を編み出しました。ダイナミック制御は人の目の曖昧さを利用した制御方法です。
 ダイナミック制御では同時点灯するLEDの数は減るものの、点灯するLEDを高速切り替えすることで
  「LEDの数≧出力端子の数」
を実現しています。

制御方式 概要 完全同時点灯
スタティック制御 個別に点灯、消灯状態を維持する制御 可能
ダイナミック制御 高速点滅を繰り返し見掛け上は同時点灯している様に見せる制御 条件による

 このダイナミック制御を解説する上で避けては通れないのが「PWM制御」です。

 PWM制御は Pulse Width Modulation の略です。簡単にいえば
高速でオンとオフの時間を制御します。
 この制御方法をLEDに適用するとLEDの見掛け上の輝度をソフトウェアから制御できるようになります。

 PWM制御はLEDだけでなくモーター制御や電圧制御にも応用できるので覚えておくと便利です。


 応用編その1: 複数LED制御 
 応用編その2: 10ポイントRGB LEDアレイ 

■キーワード

 周期に対するオン時間の比率をデューティー(Duty)と称します。
 例えば、周期が100msでオン時間が20msであればデューティー20%になります。

 Dutyが指定された場合は言葉の意味合いに確認が必要です。

 ハードウェアの都合でCPU端子~制御端子(LED素子)の間に反転回路が含まれるかもしれません。解釈を誤ると逆の結果が得られてしまうので回路図、もしくはハードウェア担当者に確認することが大切です。

 余談ですが、モーター物は一番解釈が難しいです。回路要因だけでなくメカ要因が加わります。歯車1つ加わると逆回転してしまいます。

 間違えて解釈すると機器を壊す恐れがあるので注意してください。

■LEDの輝度調整

 LEDをPWM制御した場合の動作イメージを以下に示します。

 LEDのPWM制御は点灯と消灯の組み合わせです。この時、
 ・単位時間当たりの総点灯時間が長ければ長いほど人の目には明るく感じられます。
 ・単位時間当たりの総点灯時間が短ければ短いほど人の目には暗く感じられます。

になります。
 長ければ長いほど…短ければ短いほど…時間に関しては具体的な尺度はありません。LEDに流す電流の値、利用するLEDによっても異なります。また、LEDの輝度調整は人の目の曖昧さを利用しているので、個人差があることに注意してください。

 単位時間という表現も曖昧です。比較的短時間である100msでも単位時間として定義できますが、100msでPWM制御を行うと明らかに点滅であることが判明します。およその目安ですが50ms以下の単位時間を推奨します。

 LEDの消費電力は点灯時間の累計に比例します。点灯時にのみ電力を消費し、消灯時の電力消費は無視できるほど小さいです。ということは、PWM制御を利用することで低消費電力の機器を作成することができます。が、度を過ぎると輝度が低下して意味をなさなくなります。

■プログラミング手法

(1)時間の監視 その1

 PWM制御は周期的な点灯と消灯を制御することにあります。制御時間の乱れは輝度の乱れを招くので、時間監視を正確に行うことが大切です。

 時間の監視方法には大きく分けて絶対時間と相対時間の2通りがあります。

監視方法 時間の計測基準 遅延累積 待機中の他の処理の動作
絶対時間 ハードウェアタイマ なし 可能
相対時間 ソフトウェアタイマ あり 不可能(遅延を招く=輝度がばらつく)

 どちらの方法でもPWM制御の時間監視に利用できますが、概して「PWM制御だけを行えば済む」というシステムは存在しません。点灯時にはPWM制御を利用しますが、信号の状態や通信による消灯操作を判断しなければならず、その処理時間は「ゼロ」ではありません。相対時間で時間を監視する場合、これらの処理時間を考慮しなければなりません(これが面倒)。

 PWM制御を行う上で時間監視の正確性と他の処理が同時動作できるか否かは重要なポイントです。

(2)時間の監視 その2

 点灯、消灯の各時間を監視する方法には大きく分けて単純監視と分割監視の2通りがあります。

 単純監視方式では点灯時間、消灯時間を単純に待機する方法です。タイムアウトを検出で直ちに点灯、消灯作業を行います。
 制御対象が1つであれば問題ありませんが、複数制御をおこなう場合、タイマ資源が少ない場合に使い勝手が悪くなります。

 分割監視方式では時間間隔の共通約数をタイマの1単位とし、タイムアウト回数をカウントして真のタイムアウトを検出します。
 共通約数の設定次第で複数のPWM制御を実現、またPWM制御以外の用途にも応用することができます。

 監視方式は好みが分かれるところですが、
 ・ハードウェアタイマの数を節約
 ・別項で解説するダイナミック制御への応用
を考慮すると、後者の分割監視方式がお勧めです(タイマ数が少ないマイコン利用時は推奨)。

 注記:

 後述のハードウェアによる制御を適用した場合は単純監視方式になります。
 最適な選択肢はマイコンの種類やシステム仕様により異なるので、
 ・タイマ資源に余裕がある場合は単純監視方式
 ・タイマ資源に余裕が無ければ分割監視方式
 ・処理時間を節約したければハードウェアによる単純監視方式
という具合で使い分ければ良いと思います。

(3)出力データの更新タイミング

 これまで点灯時間、消灯時間について解説してきましたが、LEDに対する制御を厳密に分析すると、
・PWM制御された点灯時間 … 非常に短時間
・PWM制御された消灯時間 … 非常に短時間
・単なる消灯時間 … 比較的長時間
の3種に分けられます。この3種の制御を場合分けして制御する方法もありますが、1つの問題が発生します。処理の作り方でタイムアウト検出後~出力データ更新するまでの時間が微妙に安定しません。

 全体制御周期は安定しますが、タイムアウトを検出してから出力データを更新するまでの時間が安定しません。

 時間のズレは数十us以内ですが割り込み処理を併用すると数百usまで延びる可能性があります。割り込み禁止で回避できそうですが、根本的に準備時間の差は埋まりません。

 このような問題を解消する場合は、出力データを更新する処理をできる限りタイムアウト検出直後に配置します。

 出力すべき情報を予備情報として保持し、次のタイムアウト検出タイミングで出力ポートに出力します。

 タイミングが1周期ずれますが、以後の制御も1周期ずれるので結果としてズレの蓄積はありません。

 この方式でも割り込み処理併用時の問題は残ります。

 メイン処理でPWM制御をおこなう場合は処理時間、割り込み処理に注意してください。できることならばPWM制御はメイン処理で行うよりも優先度の高いタイマ割り込み処理を用意し、その中で制御する方が無難です。

■ハードウェアによる制御方法

(1)CPU内蔵のPWM制御機能

 これまでソフトウェアによるPWM制御について説明してきましたが、利用するマイコンによってはPWM制御機能を内蔵している種類があります。

 マイコン内蔵のPWM制御機能の特徴は以下の通りです。
 ・出力端子の1つが制御出力用に利用される … PWM制御機能を利用しなければ汎用入出力として利用可能
 ・動作を開始すると、停止を明示するまでPWM制御を自動的に行う。

 PWM制御中にプログラムに対する負荷は無く、別の作業を行うことができます。便利な機能なので利用するマイコンのデータシートを確認してみてはいかがでしょう。

(2)動作イメージ

 マイコンの種類により設定方法、動作方法は異なると思いますが、ほぼ以下の様な動作になります。
 上段がPWM制御機能で利用されるカウンタの値で下段が制御出力端子の状態です。

 0からスタートしたカウンタの値は定期的にカウントアップされ、Dutyに対応する値に達すると制御出力端子の状態を反転します。カウントは更に継続しCycleに対応する値に達すると再度制御出力端子の状態を反転すると共にカウンタの値は0に戻ります。

 マイコンの種類によっては、更に高度な機能を持つ種類があります。
 ・最初の出力状態を設定できる。
 ・外部入力に連動してPWM制御機能の動作を開始、停止する。

 PWM制御機能は便利な機能ですが、たいていの場合、マイコン内蔵のタイマ機能を利用するのでソフトウェアから見ると利用可能なタイマが少なくなってしまいます。ですが、それに見合うだけの機能を発揮してくれます。

 カウンタの大きさは1バイト、もしくは2バイトでです。このカウンタを源発振を分周したタイミングで更新しますが、カウンタの大きさに制限があるので結果として制御可能な値に制限が生じます。それ故、
高速なPWM制御は得意ですが、低速なPWM制御は不得意であることに注意してください。

(3)接続イメージ

 端子の許容電流の条件により様々な接続方法がありますが…。利用例の一部を挙げると以下の様になります。

一般

 ハードウェアによるPWM制御ではなく、ソフトウェアによりPWM制御を行います。

直接接続

 PWM制御出力端子の許容電流が大きい場合に利用できます。

トランジスタ接続

 PWM制御出力端子の許容電流が小さい場合はトランジスタを接続してLEDに大電流を流せるようにします。

複数LEDのPWM制御

 複数のLEDのPWM制御を同時に行います。複数のLEDが同時点灯するのでトランジスタを接続して大電流を流せるようにしています。

 高輝度タイプのLEDであれば小電流でも点灯できるので、そのような場合はPWM制御出力端子に直接接続できる場合があります。

(4)消灯状態の実現

 PWM制御出力中はオン状態とオフ状態の繰り返しであり、見た目は点灯状態です。
 では消灯状態を表現するにはどうしましょう?

 PWM制御出力端子は汎用出力端子の機能と兼用していることが多いです。
 そこで、単純にPWM制御機能を停止し、汎用出力端子に切り替えることで消灯状態を実現するのが簡単です。

 なお上図の「複数LEDのPWM制御」の場合ではPWM制御出力を維持した状態でも「LED CTL」端子の制御のみで消灯を実現することができます。

(5)注意事項

 上述の消灯実現方法は力技です。利用するマイコンが備えるPWM機能によっては、DutyとCycleの値とバランスにより点灯、もしくは消灯状態を維持できる場合があります。例えば Duty > Cycle の様な設定です。
 また、値変更時に現在のPWM動作を乱さないようにバッファが用意され、次の周期で有効になるような「カラクリ」が用意される場合もあります。詳しくは利用するマイコンのデータシートを確認願います。

 明示的にPWM機能が搭載されていない場合でも内蔵タイマのタイムアウトで出力ポートが変更できるのであれば疑似的なPWM機能を利用することができます。点灯比率が50%であれば非常に簡単です。もし点灯比率を操作するのであればタイムアウトで出力ポートを変更したのち、割り込みを発生させ、ソフトウェアでタイムアウト値を操作することで実現できる可能性があります。ただし、周期が短い場合、比率に偏りがある場合は割り込み処理が間に合わない場合があります。
 それでも、ソフトウェア制御による遅延問題を回避できる可能性があるので検討してみてはいかがでしょう?

■サンプルプログラム(その1:点灯比率固定)

(1)テーマ

 割り込み処理を使用しないソフトウェアPWM制御のサンプルプログラムです。
 マイコンにはPIC12F683を使用し、PWM制御によるLEDの表示具合を目で見て確認します。

 装置電源をオンすると、最初の5秒間は総てのLEDが点灯し、続いてPWM制御に移行します。
 各LEDの
PWM制御周期はLED0が100ms、LED1が50ms、LED2が10ms。点灯比率は50%固定です。

 マイコン内蔵のタイマ0を利用します。源発振と分周の関係で1ms単位の制御は実質1024usになります。

(2)回路図、部品の配置

 毎度おなじみ、初級編で利用した回路を利用します。マイコンはPIC12F683です。
 ブレッドボード上のLEDは左からLED0/1/2、スイッチは左からSW0/1の順番で配置します。

 注意:今回はスイッチを利用しないので実装は任意です。

X1はGND、Y1は3.0Vを接続します

(3)プログラム本体

 サンプルプログラムを公開します … TestPwm0100.zip 将来的に課題が残ります。詳しくはジャンプ
 サンプルプログラムを公開します … TestPwm0101.zip 2010.04.20 
こちらを利用してください。

 開発環境は MPLAB IDE V8.40 と HI-TECH C V9.70 を利用しています。

 HI-TECH C v9.70 で作成されたプログラムを v9.81 以降のコンパイラで再コンパイルする際の注意点
  → 開発環境による修正 2011/03/09

(4)少しだけ解説

 今回のサンプルプログラムを利用するとLED表示は以下の様になります。

 点灯比率(Duty)は50%固定で制御周期だけが異なります。
 プログラムを見ると手抜きが1ヶ所(汗)。5秒点灯後、最初の点灯制御前に全消灯になる期間が存在します。

 プログラムの内容はソースプログラムを見ていただく方が早いのですが、概略フローチャートではこんな感じです。


 初期設定後、以後は制御を繰り返す無限ループです構成です。
 タイマ0は1024usでタイムアウトする様に設定していますが、割り込みは使用しません。

 タイムアウト監視ではタイムアウトをポーリングで検出するだけです。
 
タイマ0は動作を継続するので、次のタイムアウト前に再度監視を行うようにします。

 出力データは予め予備情報として用意し、タイムアウト直後に一括出力します。


 制御データはLED毎に専用の構造体に用意されます。
 3つのLEDをfor文ではなく個別演算していますが、これはアドレス計算(乗算)を抑止するためです。高性能なマイコンであればfor文で回しても良いと思います。

 制御データ準備の処理を少しだけ拡大。

 とりあえず左図の様な力技的な関数を用意しました。

 どちらかというとLEDを長周期点滅(ex.1秒周期)させる為の処理に近いです。

 この処理を約1msという周期で毎回行うのは気が引けるのですが、今回はサンプルということで ^ ^ ;


 そうそう。カウントの初期値は1です。0で突入はありません。

(5)動作結果

 100ms、50msの制御周期では点滅していることが分かります(個人差があります)。
 10msの制御周期、点灯比率50%では連続点灯しているように見えますが少しだけ輝度が低下します。

■サンプルプログラム(その2:制御周期固定)

(1)テーマ

 割り込み処理を使用しないソフトウェアPWM制御のサンプルプログラムです。
 マイコンにはPIC12F683を使用し、PWM制御によるLEDの表示具合を目で見て確認します。

 装置電源をオンすると、最初の4秒間は総てのLEDが点灯し、続いてPWM制御に移行します。
 各LEDの
PWM制御周期は10ms固定、点灯比率はLED0が80%、LED1が40%、LED2が10%です。

 マイコン内蔵のタイマ0を利用します。源発振と分周の関係で1ms単位の制御は実質1024usになります。

 前述の「サンプルプログラム(その1)」との違いは制御周期を固定にするか、点灯比率を固定にするか。です。

(2)回路図、部品の配置

 前述の「サンプルプログラム(その1)」と同じ構成です。

(3)プログラム本体

 サンプルプログラムを公開します … TestPwm0110.zip 将来的に課題が残ります。詳しくはジャンプ
 サンプルプログラムを公開します … TestPwm0111.zip 2010.04.20 こちらを利用してください。

 開発環境は MPLAB IDE V8.40 と HI-TECH C V9.70 を利用しています。

 HI-TECH C v9.70 で作成されたプログラムを v9.81 以降のコンパイラで再コンパイルする際の注意点
  → 開発環境による修正 2011/03/09

(4)少しだけ解説

 今回のサンプルプログラムを利用するとLED表示は以下の様になります。

 制御周期は10ms固定で点灯比率だけが異なります。
 プログラムを見ると手抜きが1ヶ所… プログラムの構成が同じなので手抜きの個所も同じです orz

 プログラムの構成は前述の「その1」と同じです。制御用情報の初期設定データ(初期化済み定数)が異なります。

(5)動作結果

 
点灯比率が高いほど輝度が高く見えます。厳密には高速点滅しているのですけどね(人の目が騙されているw)。
 LEDの種類や流す電流値によりメリハリが付きにくいかもしれませんが、試しにデジカメで撮影してみました。

 LEDは左からLED0/LED1/LED2になります。
 点灯比率が高いほど輝度が高く見えます。

 デジカメ画像のプロパティを見ると撮影時の状況を確認することができます。今回の映像の場合、はシャッター速度は1/31sec(約32ms)でした。

 デジカメの
シャッター速度が早すぎると消灯タイミングを撮影してしまう場合があるので注意してください。

 交差点にある信号機。最近はLEDが利用されています。この種の信号機にはダイナミック制御と呼ばれるPWM制御の大掛かりな仕掛けが利用されています。
 さて、この信号機をデジカメに限らずデジタルビデオカメラで撮影する際、周囲が明るいと自動的にシャッター速度が高くなり…結果として信号機が点灯していない。ということがあります。

(6)おまけ

 今回の実験ではオシロスコープを利用して波形を確認しました。
 ただ、オシロスコープは何処の御家庭にも…。簡単な確認方法を利用してみてはいかがでしょう?

 その方法とは…「
LEDを振る」。です。

 なかなか綺麗に取れないのですが…

 縦向きにしたので、上から順にLED0/LED1/LED2になります。点灯比率は80%/40%/10%の順で、その長さの違いを見ることができます。

 デジカメの感度を低くすることでシャッター速度を下げました。今回の場合は結果的に1/4sec(250ms)です。

 手による往復運動でなので等加速度運動になっていませんが、およそ25個の点滅が見てとれます。

 この写真から色々なことが分かります。

 ・250msのシャッター速度で25個の点滅であれば点灯のタイミングは10ms周期(今回の写真では厳しい…)。
 ・背景にある目盛りは1cm間隔。3個の点滅であれば1cmを30msで移動しているので、33.3cm/sの移動速度。
 ・点灯部分と消灯部分の長さを図ることで点灯比率が判明。

 まぁ、デジカメが記録した映像に含まれるシャッター速度情報が正確であること、等加速度運動が前提ですが(汗

 この現象を利用した「バーサライタ」と呼ばれる装置があります。検索すると沢山ヒットしますよ ^ ^ v

■サンプルプログラム(その3:割り込み)

(1)テーマ

 
割り込み処理を使用したソフトウェアPWM制御のサンプルプログラムです。

 動作内容は前述の「サンプルプログラム(その2:制御周期固定)」と同じです。

(2)回路図、部品の配置

 前述の「サンプルプログラム(その1)」と同じ構成です。

(3)プログラム本体

 サンプルプログラムを公開します … TestPwm0120.zip 将来的に課題が残ります。詳しくはジャンプ
 サンプルプログラムを公開します … TestPwm0121.zip 2010.04.20 
こちらを利用してください。

 開発環境は MPLAB IDE V8.40 と HI-TECH C V9.70 を利用しています。

 HI-TECH C v9.70 で作成されたプログラムを v9.81 以降のコンパイラで再コンパイルする際の注意点
  → 開発環境による修正 2011/03/09

(4)少しだけ解説

 前述の「サンプルプログラム(その2:制御周期固定)」とプログラムの内容が少しだけ異なります。

 これまでメイン処理で行っていたタイムアウト監視をマイコンに一任し、それ以外の各処理を割り込み処理に移動しました。制御の「キモ」となる部位が移動しただけで制御手法に変更はありませんが、メイン処理における処理時間の自由度が大きくなります。

 今回はサンプルプログラムなので変数の排他制御を行っていませんが、メイン処理で出力ポートに関わる操作を行う場合は排他制御(割り込み禁止、変数に対してvolatile属性付与)を行わなければなりません。

■サンプルプログラム(その4:ハードウェアPWM機能)

(1)テーマ

 割り込み処理とマイコンが備える
ハードウェアPWM制御のサンプルプログラムです。
 マイコンにはPIC12F683を使用し、PWM制御によるLEDの表示具合を目で見て確認します。
 ハードウェアPWM制御可能な端子はGP2に割り当てられています。

 装置電源をオンすると、最初の3秒間は総てのLEDが点灯し、続いてPWM制御に移行します。

 LED0/LED1はソフトウェアPWM制御です。
制御周期は10ms固定、点灯比率はLED0が10%、LED1が50%です。
 LED2はハードウェアPWM制御です。
制御周期は1ms固定。点灯比率は50%です。

 マイコン内蔵のタイマ0を利用しますが源発振と分周の関係で1ms単位の制御は実質1024usになります。
 ハードウェアPWM制御にタイマ2を利用します。1msを設定できますがタイマ0に合わせて1024usを利用します。

(2)回路図、部品の配置

 前述の「サンプルプログラム(その1)」と同じ構成です。

(3)プログラム本体

 サンプルプログラムを公開します … TestPwm0130.zip 将来的に課題が残ります。詳しくはジャンプ
 サンプルプログラムを公開します … TestPwm0131.zip 2010.04.20 こちらを利用してください。

 開発環境は MPLAB IDE V8.40 と HI-TECH C V9.70 を利用しています。

 HI-TECH C v9.70 で作成されたプログラムを v9.81 以降のコンパイラで再コンパイルする際の注意点
  → 開発環境による修正 2011/03/09

(4)少しだけ解説

 今回のサンプルプログラムを利用するとLED表示は以下の様になります。
 これまでのサンプルプログラムとちょっと違います。

 LED0/LED1はソフトウェアPWM制御です。構成は前述の「サンプルプログラム(その3:割り込み)」と同等です。

 LED2はハードウェアPWM制御です。初期設定だけで以後はソフトウェアの介在無しにPWM制御を繰り返します。

 PICマイコン全般に言えますが、データシートが見難い…。
 極論を言えば、
  ・制御周期= (PR2 + 1) * 4 * Tosc * TMR2プリスケーラ
  ・点灯時間= 10bitデータ * Tosc * TMR2プリスケーラ
です。。この式を逆算すれば設定値を求めることができます。

 源発振が4MHzであれば、Toscは0.25usです。TMR2プリスケーラは1/4/16から選択します。
 TMR2プリスケーラが4。制御周期1024us、点灯比率50%(1024/2=512us)であれば、
  ・制御周期の設定値= PR2 = (1024 / 4) - 1 = 255
  ・点灯時間の設定値= 10bitデータ = 512 / 4 = 128
になります。点灯時間の値は「-1」補正が無いので注意してください。

 PIC12F683のハードウェアPWM制御では制御周期1000us、点灯比率50%(500us)を算出できるのですが、ソフトウェアPWM制御との比較を行うために、あえて1024us、512usにしています。

 参考値ですが、
今回のサンプルでは点灯時間の設定値を「1」にするとパルス幅1usを実現できます
 ソフトウェアPWM制御では実現できませんよね。それも実行中のソフトウェアに対する負荷がありません。

(5)動作結果

 ソフトウェアPWM制御のLED1とハードウェアPWM制御のLED2の制御状態をモニタしてみました。

 各チャネルは、
 ・Ch1がGP1(LED1のアノード) … ソフトウェア制御
 ・Ch2がGP2(LED2のアノード) … ハードウェア制御
です。

 LED1の周期の中にLED2の周期が10個入っています。

 制御の開始点は合わせていません。

 点灯状態は以下の通りです。左からLED0/LED1/LED2になります。

 LED0(左)の制御周期10ms、点灯比率は10%。
 LED1(中)の制御周期10ms、点灯比率は50%。
 LED2(右)の制御周期 1ms、点灯比率は50%。

 LEDの向きが少し傾いているのですが…
 点灯比率が同じであれば輝度はほぼ同じです。

 なお、シャッター速度は1/29secでした。

(6)おまけ

 今回の実験でもLEDを振ってみました。

 前回と同様、上から順にLED0/LED1/LED2になります。

 一番下LED2は制御周期1msということもあり点滅状態を見分けることはできませんでした(汗

 シャッター速度は1/16sec(62.5ms)です。
 LED1を見ると点灯状態が6個と少し。シャッター速度との関係は良い感じです。

 コンパクトデジカメなのでシャッター速度を固定することができません。ので、次回も同条件で撮影することは困難です。 数でカバーするという話もありますが… orz

■おまけ(蛍風)

(1)テーマ

 PIC12F683内蔵のハードウェアPWM制御を利用し、
LEDの輝度を連続的(デジタルですが)に変更します。

 制御周期は2ms。点灯周期は0~2ms。
 ハードウェアPWMを動作させつつ、制御周期を司るタイマ2のタイムアウトのタイミングで点灯周期を変更します。

 2ms毎に点灯周期を4usづつ増加します。点灯周期が2msに達したら点灯周期を4usづつ減少します。
 点灯周期の変化の状態は以下の通りです。
 点灯周期の更新は4us単位ですが、実のところ制御レジスタの値をインクリメント、もしくはデクリメントしているだけです。

 制御周期固定で点灯周期を4us単位で変更すると微妙に輝度が変わるはずですが、使用するLEDの特性により輝度の状態は連続変化しない可能性もあります。

(2)回路図、部品の配置

 前述の「サンプルプログラム(その1)」と同じ構成です。
 今回はLED2だけ利用します。LED0/LED1は消灯したままです。

(3)プログラム本体

 サンプルプログラムを公開します … TestPwm0200.zip 制御方法として問題はありませんが改版します。
 サンプルプログラムを公開します … TestPwm0201.zip 2010.04.20 
こちらを利用してください。

 開発環境は MPLAB IDE V8.40 と HI-TECH C V9.70 を利用しています。

 HI-TECH C v9.70 で作成されたプログラムを v9.81 以降のコンパイラで再コンパイルする際の注意点
  → 開発環境による修正 2011/03/09

(4)少しだけ解説

 PIC12F683内蔵のハードウェアPWM(他のPICマイコンでも同等と思います)は制御周期に関するレジスタが1つ、点灯周期に関するレジスタが2つあります。

 点灯周期を設定するレジスタがポイントです。
一方が現在実行中の情報、他方が次回に利用される情報です。
 制御周期到達後、次回用の情報は実行中の情報に自動的にコピーされます。
 レジスタが2つあることで制御周期の切り替わりで息切れ(波形の予定外の乱れ等)がありません。

 点灯周期は10bitで構成されます。結果として8bit+2bit で2回のバイトアクセスが必要です。このアクセスは値の一貫性を保つために連続して行う必要があり、今回のサンプルプログラムではタイマ2の割り込み処理(制御周期の間隔に等しい、もしくは制御周期の先頭に等しい)で作業しています。

(5)動作結果

 連続動作するので動画を張り付けたいところですが…。各自で動作確認してみてください。
 約1秒で輝度が上昇し、約1秒で輝度が下降する繰り返しの動作を確認できると思います。

(6)おまけ

 今回の動作例はマイコンを使用せずともハードウェア回路だけで実現することができます。ですが、任意の輝度傾きを再設定する場合、ロウソクの炎の様な表現を行う場合はマイコン制御が有利です。

 さて。

 連続変化の任意点を人間に把握させるのは困難です。単独表示している場合に「今100…今250…」という具合で区別することができません。輝度の変化させる場合は3段階(明点灯、暗点灯、消灯)程度に抑えた方が無難です。

 今回はLEDを利用したので連続変化の有用性は今一つでしたが、メカ制御、例えばラジコン等で使用されるサーボモーターを制御する場合に連続変化は有用です。変化させた状態が動きとして増幅されるので、たとえ4usの違いでも結果が見えると思います。

 今回使用したPIC12F683では運用中に点灯周期を操作できますが、制御周期を操作する場合はレジスタが1つ故、制御周期の切り替わり目であるタイマ割り込みを駆使する必要があります。ですが、マイコンによっては制御周期に関するレジスタが2つあり、実行中情報と次回情報に分けて管理されている場合があります。

■サンプルプログラムの問題点と対応

(1)はじめに

 サンプルプログラム(XX.X0系、いわゆる0系)を5本掲載しましたが…少しだけ問題がありました。
 同じ調子でプログラムを作成したものだから、問題点が波及してしまい (ry

 今回のサンプルプログラムは、各テーマに準じている限りは問題ありません。
 表示タイミングの変更や表示の仕方を変えても問題ありません。

 が、この方法を残すのも「アレ」なので、しれっと修正します。

(2)問題点

 LEDへの点灯内容を出力ポートにビット操作なしで出力する方法。これは問題ありません。むしろ推奨。
 問題は
LED点灯消灯制御時、出力ポート用のバックアップ情報を直接修正していたことです。


 これが最初の構成です。特に問題ありません。

 制御データを準備して、それを次回のタイムアウトのタイミングで出力する。
 うーん。理想的な方法じゃないですか。ははは…

 数日経過し、別項で複数LEDの制御を作っていて気がついた。
 
制御データを準備する処理で出力データのバックアップ変数に直接書き込んでいる。

 もしかして、これはやばいかも…

 いや、今はいいのだけどね。将来的に問題がある。
 今はいいのだけどね… 大切な事なので2度言いました。


 今回のサンプルプログラムで問題が起きないケースです。

 LED制御以外の出力ポートを操作する命令、ハードウェアを組み込んだ状態です。

 出力ポート操作は、ビット操作ではなく、一旦バックアップ変数を更新し、バイト操作で出力ポートに書き込む(これ自体はPICマイコン固有の操作かも…)を基本とします。

 出力ポートに書き込む操作は、左フローチャートでは黄色と青色の部位になります。

 この方法であれば問題が表面化しないのですよね。

 なぜならば、
巡回の最終段でLEDの制御データを準備(緑色)しているからです。
 この方法であれば見た目のLEDの点灯、消灯周期は補償されます。
 プログラム修正前のLED制御タイミングと同じです。


 今回のサンプルプログラムで問題が起きるケースです。

 動作条件は前述の変更と同じですが…

 LED制御以外の出力ポートを操作する部位(青色)がLEDの制御データを準備する部位(緑色)の後ろにあります。

 出力ポート操作がバックアップ変数を更新してからバイト操作で出力ポートに書き込む方法を踏襲した場合に問題が発生します。

 問題点は、
 バックアップ変数に対してLEDの制御データが書き込まれているため、次の出力データ更新を待たずにLEDの点灯、消灯の状態が書き変わってしまう。
です。

 おそらく、LEDの定周期制御が崩れて「ちらつき」が発生すると思います。

(3)解決方法

 LEDに反映するタイミングをタイムアウト直後に限定すれば解決できます。その為に変数を1つ追加します。
 具体的な変更方法は、

 変更前:
  LED制御データ準備でバックアップ変数を編集。

 変更後:
  LED制御データ準備で専用変数を編集。タイムアウト後の出力データ更新直前でバックアップ変数に反映。

 変数は増えるものの、無難な変更方法と思います。

 変更後のプログラムは既存の版数の直下に配置しますので、ダウンロードに関しては各所を参照願います。

(4)その他

 修正して気がつきました。0130、0200は私の開発環境以外ではソースファイルの読み出しに失敗します。
 プロジェクトのSourceFileの個所で対象ファイルを削除し、再度追加すれば問題は解消します。

 しかし…

 おそらく、プロジェクトを新規作成の過程(ウィザード)でソースファイルを直接指定したためだと思います。
 プロジェクトファイルである「拡張子mcp」を確認したら絶対パス名で登録されていました。なぜ?

 ソースファイルの登録はウィザードを完了した後に手動で追加しないと相対パス設定が生きてこないようです。

 2010.04.19 新規作成

Copyright 2010,2011 PaletteSoft LLC. All rights reserved. 利用条件 | HOME | サイトマップ | お問合せ
PWM 制御 LED 輝度 消費電力 節電 タイマ DUTY デューティ スタティック ダイナミック 点滅