2013/07/27からのアクセス回数 4777 PWM(Pluse Width Modulation)を使う †LEDの明るさを変えるには、周期的にLEDのON/OFFを繰り返し、ONの時間を変える方法がPWMです。 LEDとの接続 †MyARMのp21からp26までのPWMにIOピンの内、PWMに使えそうなのはp21, p23, p26ですが、 p21でLPC-LinkのSWCLKで使っているので、LPC-Linkを使っている人は絶対に指定しないで下さい。 *1 p23はM3であり、_timer32.cライブラリがM3をリセットに使用しているため動作しませんでした。 IOにLEDを接続する場合、IOをHighの場合のLEDを点灯する正論理と、IOがLowの場合に場合に点灯する負論理が あります。*2 今回は、負論理でp26にLEDのカソードをつなぎ、アノード*3に470Ωの抵抗を直列につなぎ、3.3Vに接続しています。 サンプルプログラム †サンプルプログラムでは、PwmOutのインスタンスledを生成し、200m秒毎に0.05ずつ値を大きくする (明るさを少なくする)もので、これを4秒間隔で繰り返します。 #include<cr_section_macros.h> #include<NXP/crp.h> __CRP extern const unsigned int CRP_WORD = CRP_NO_CRP ; #include "lbed.h" int main(void) { wait_init(); PwmOut led(p26); led = 0.0; while(1) { led = led + 0.05; wait_ms(200); if(led >= 1.0) { led = 0.0; } } } PWMOutクラスの実装 †サンプルプログラムのPWMを参考にPWMOutクラスを作成します。 最初、timer16.c, timer32.cのsetMatch_timer16PWM, setMatch_timer32PWM関数は、HEIGHTからLOWに変化するものと 勘違いして、pulsewidthを実装していたのですが、以下のタイマー機能の説明によるとLOWからHEIGHTになるものだと分かりました。 タイマー機能を使ってPWMを実装する場合の説明が、トラ技2012年10月号の図13にあるので、引用します。 いつものように、サンプルのtimer16.[hc], timer32.[hc]の先頭に_を付け、ヘッダファイルの先頭の__TIMER16_Hの後に、 extern文を追加し、 #ifndef __TIMER16_H #define __TIMER16_H #ifdef __cplusplus extern"C" { #endif 最後に #ifdef __cplusplus } #endif #endif/* end __TIMER16_H */ を付けて、C++からCの関数が使えるようにします。 PwmOut.cppのソースは、以下のようにしました。 ((最初、16bitのことをうっかり忘れ、periodが16bitをオーバーしたために、不可解な動作をしましたが、 プレスケールをセットすることで対応しました。)) #include "platform.h" #include "PinNames.h" #include "PwmOut.h" #include <LPC11xx.h> #include "type.h" #include "_timer16.h" #include "_timer32.h" #define NULL (0L) PwmOut::PwmOut(PinName pin) : _name(NULL), _period(0.02), _pulsewidth(0.0), _value(0.0), _scale(1) { _pin = pin; setup(_period); /* Enable AHB clock to the GPIO domain. */ LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6); } void PwmOut::setup(float period) { _period = period; uint32_t p = (uint32_t)(SystemCoreClock*_period); // 16bitの範囲内で制御できるようにprescaleを変更する if (p > (SystemCoreClock/1000)) _scale = 1000; else _scale = 1; uint32_t matchTime = (uint32_t)((_period - _pulsewidth)*SystemCoreClock/_scale)-1; // PWMに使えるのは、p21-23, p26です。 switch (_pin) { case p21: // PIO0_10 CT16M2 LPC_TMR16B0->PR = _scale -1; // prescaleをセット init_timer16PWM(0, p/_scale, MATCH2, 0); setMatch_timer16PWM (0, 2, matchTime); enable_timer16(0); break; case p22: // PIO0_2 CT16B0C0 break; case p23: // PIO0_11 CT32M3 LPC_TMR32B0->PR = _scale -1; // prescaleをセット init_timer32PWM(0, p/_scale, MATCH3); setMatch_timer32PWM(0, 3, matchTime); enable_timer32(0); break; case p25: // PIO1_8 CT16B1C0 break; case p26: // PIO1_9 CT16M0 LPC_TMR16B1->PR = _scale -1; // prescaleをセット init_timer16PWM(1, p/_scale, MATCH0, 0); setMatch_timer16PWM (1, 0, matchTime); enable_timer16(1); break; } } void PwmOut::period(float seconds) { setup(seconds); } void PwmOut::pulsewidth(float seconds) { _pulsewidth = seconds; uint32_t matchTime = (uint32_t)((_period - _pulsewidth)*SystemCoreClock/_scale)-1; // PWMに使えるのは、p21, 23, p26です。 switch (_pin) { case p21: // PIO0_10 CT16M2 注意)LPC-Linkを使っている場合には設定してはいけない! setMatch_timer16PWM (0, 2, matchTime); break; case p22: // PIO0_2 CT16B0C0 break; case p23: // PIO0_11 CT32M3 setMatch_timer32PWM(0, 3, matchTime); break; case p25: // PIO1_8 CT16B1C0 break; case p26: // PIO1_9 CT16M0 setMatch_timer16PWM (1, 0, matchTime); break; } } void PwmOut::disable(void) { // PWMに使えるのは、p21, 23, p26です。 switch (_pin) { case p21: // PIO0_10 CT16M2 注意)LPC-Linkを使っている場合には設定してはいけない! disable_timer16(0); break; case p22: // PIO0_2 CT16B0C0 break; case p23: // PIO0_11 CT32M3 disable_timer32(0); break; case p25: // PIO1_8 CT16B1C0 break; case p26: // PIO1_9 CT16M0 disable_timer16(1); break; } } コメント †皆様のご意見、ご希望をお待ちしております。
Tweet |