lbed

2013/07/27からのアクセス回数 4552

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に接続しています。

PWMSetting.png

サンプルプログラム

サンプルプログラムでは、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にあるので、引用します。 Fig13-TRG.png

いつものように、サンプルの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;
	}
}

コメント

選択肢 投票
おもしろかった 0  
そうでもない 0  
わかりずらい 0  

皆様のご意見、ご希望をお待ちしております。

  • PwmOutの動作がおかしいので、ソースの公開は待って下さい。 -- 竹本 浩? 2013-07-28 (日) 13:47:10
  • プリスケールを追加して何とか動くようになりました。 -- 竹本 浩? 2013-08-03 (土) 15:17:54

(Input image string)


*1 私も試しに指定してその後、LPC-Linkが使えなくなって大変でした。シリアルからプログラムを書き込みMagicFlashで別のプログラムを書き込んで復活しました。
*2 正論理でLEDが消灯しない問題は解決しました
*3 線の長い方

添付ファイル: filePWMSetting.png 1167件 [詳細] fileFig13-TRG.png 1201件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2013-08-03 (土) 15:17:54 (3920d)
SmartDoc