TWELITE ZONE

TWELITEのガチプログラミングを推進する非公式サイト

タイマー/PWM/アナログ出力 概要


もくじ - TWELITE ZONE


TWELITE用ライブラリ basicio.h のタイマー/PWM/アナログ出力の概要です。これらはすべてタイマー機能を使っているため、関数名はtimer_で始まります。




タイマーとピンの割り当て

5つのタイマーがあり、これらはタイマー割り込みとして使用できます。またPWMやアナログとして出力する場合は、出力先のDIOピンが以下のように割り当てられています。
()内はセカンダリピンで、関数呼び出し時にどちらを使うか指定できます。

Timer0 Timer1 Timer2 Timer3 Timer4
PWM/アナログ
使用時の出力先
DIO10
(DIO4)
DIO11
(DIO5)
DIO12
(DIO6)
DIO13
(DIO7)
DIO17
(DIO8)

ひとつのタイマーに対しいずれかの機能(タイマー割り込み、PWM出力、アナログ出力)1つを割り当てることができます。
PWM出力またはアナログ出力を使用しない場合、それらのDIOは汎用DIOとして利用できます。



プリスケーラと16ビットカウンタ

基本周波数16MHzを(2^プリスケーラ)によって分周し、その分周されたクロックで16ビットカウンタがインクリメントされます。
16ビットカウンタが一定値に到達(カウントアップ)したときにタイマーイベントなどが発生する仕組みです。

例えば、プリスケーラーが4の場合、16000000Hz / (2^4) = 1000000Hz となり、分周されたクロックは1クロックあたり1秒/1000000Hz = 0.000001秒 = 1μ秒となります。
16ビットカウンタに1000を設定すれば、1μ秒 x 1000 = 1ミリ秒となり、1ミリ秒毎にイベントを発生させることができます。

計算が少しややこしいので、下記で計算ツールを紹介しているので参考にしてください。



機能の有効化

タイマー/PWM/アナログ出力機能を使用する場合は、basicio_module.hで USE_TIMER のコメントを外して宣言する必要があります。これにより関連する関数がコンパイルされるようになります。

//basicio_module.h

/* タイマー/PWM 機能 */
#define USE_TIMER




タイマー割り込み

一定周期でコールバック関数を呼び出します。コールバック関数の登録にはtimer_attachCallback()関数を使用します。
bool_t timer_attachCallback(uint8_t timerNo, uint8_t prescale, uint16_t cycleCount, void (*func)())
ここでcycleCountが16ビットカウンタのカウントアップ値になります。
これらのパラメータは下記URLで簡単に計算できるようにしました。
basicio.h タイマー、PWM設定値計算 - TWELITE ZONE

#include "basicio.h"
//basicio_module.hでUSE_TIMERを有効にしておくこと

#define TMRNO 0    //使用するタイマーNo 0~4

//タイマーコールバック関数。一定周期で呼び出される。
void tmr() {
    static int b = 0;
    dio_write(1, ++b & 1); //ここでは単純にDIO1にON/OFF出力
}

void setup(bool warmWake, uint32 dioWakeStatus) {
    //DIO1を初期化
    dio_write(1, LOW);
    dio_pinMode(1, OUTPUT);

    //タイマーコールバックを設定
    timer_attachCallback(TMRNO,
            9,          //プリスケーラー
            15625,  // 15625/(16000000/(2^9)) = 0.5秒毎
            tmr);     //コールバック関数
    timer_start(TMRNO); //これで開始
}




PWM出力

PWMを出力する場合はtimer_attachPWM()関数を使用しますが、
bool_t timer_attachPWM(uint8_t timerNo, uint8_t prescale, uint16_t cycleCount, uint16_t midCount, bool_t bStartFromHi)
ここで、cycleCountは周期を設定する16ビットカウント値、midCountが周期の途中で信号が変化(L->HまたはH->L)するまでのカウント値、bStartFromHiが周期の開始時の信号レベル(LまたはH)を決めるパラメータになります。
例えばcycleCount=1000でmidCount=500であれば、midCountがちょうど半分なのでデューティー比50%のPWM波形を出力します。
これらのパラメータ値は下記URLで簡単に計算できるようにしました。
basicio.h タイマー、PWM設定値計算 - TWELITE ZONE

f:id:mae8bit:20190912154701p:plain
PWM設定パラメータのイメージ

また、サーボの制御のようにパルス幅(midCount値)を変動させる関数を準備しました。
bool_t timer_updatePWMDuty(uint8_t timerNo, uint16_t midCount)

#include "basicio.h"
//basicio_module.hでUSE_TIMERを有効にしておくこと

#define TMRNO 1    //使用するタイマーNo 0~4

void setup(bool warmWake, uint32 dioWakeStatus) {
    //PWMを設定
    // 40000/(16000000/(2^3)) = 0.02秒 = 20ミリ秒
    // 20ミリ秒 x (2400 / 40000) = 1.2ミリ秒
    timer_attachPWM(TMRNO,
            3,            //プリスケーラー
            40000,    // 20ミリ秒周期
            2400,      //1.2ミリ秒のパルスを出力
            FALSE,    //波形 L->H
            FALSE);   //タイマー1のメインピンDIO11に出力(TRUEの場合DIO5)
    timer_start(TMRNO); //これで開始
}

void loop() {
        :
    //パルス幅を変更するだけなら、この関数のほうが軽量
    timer_updatePWMDuty(TMRNO, 1000); //パルス幅を0.5ミリ秒に変更する
        :
}




アナログ出力

TWELITEはデルタシグマ変調により、低速のDACとしての機能を持っています。TWELITE自身はNRZとRTZの出力方式に対応していますが、basicioではNRZを用いてアナログ出力としています。コンデンサと抵抗をきちんと選定すれば電圧が得られるのでしょうが、ハードウェアはあまり得意でないので深くは述べません。
単純にArduinoのanalogWrite()的に使えると思います。

#include "basicio.h"
//basicio_module.hでUSE_TIMERを有効にしておくこと

#define TMRNO 2    //使用するタイマーNo 0~4

setup() {
        :
    timer_attachAnalogWrite(TMRNO,
            32768,     //50%出力。範囲は1~65536(0)、1が最小、0が最大
            TRUE);     //タイマー2のセカンダリピンDIO6に出力(FALSEの場合DIO12)
        :
}

void loop() {
        :
    //出力を変更するだけなら、この関数のほうが軽量
    timer_updateAnalogPower(TMRNO, 0); //100%出力
        :
}