本チュートリアルではREOボードを使用した外部信号の測定方法を説明する。PWMを使用したLEDのデューティー比の変更方法は説明済みなので、そのコードを再利用しポテンショメーターからLEDを制御してみよう。

ADCについて

MSP430F5xには12チャンネルADCがある。この全チャンネルは個々に設定可能で複数のリファレンス電圧と比較した入力電圧の測定が可能である。ADCプログラムの説明に先立ち、ハードウェアを以下のように作製する必要がある:

左下はポテンショメーターのボードへの繋ぎ方を示す概略図である。右下の写真は、実際のハードウェアである。Reoボードの外部コネクタには全てグランドとVccがある。まずポテンショメータをアナログコネクタのVcc (+3.3V)とGNDに接続する。ポテンショメーターの中央点をA0に接続する。正負は、切り替え可能である。

Pot

 BoardAndPot320

 

 

 

 

 

 

 

 

MSP430の第1 アナログ入力であるA0を使用する。

プログラム

MSP430のADCの変換開始にはいくつかの方法がある。

  • ADC自体により決定されるタイミング
  • 別のタイマーによる変換
  • 変換機能呼び出しによる割込み無しの変換

REOボードではタイマーが他の用途にすで使用されているので、ここでは3番目の方法を選択する。LEDのデューティー比をポテンショメーターの中央ピンの電圧に比例して変更させる。

サンプルコードは以前のチュートリアルに比べ複雑になったので、本ページの最後に添付する。

機能

ソフトウェアは以下のように機能別に分割する

  • void EnableLedPWM(void); この機能はPWM用タイマーを設定する。 タイマーはLEDを直接起動させ、設定は低周波数RTCクロック(TASSEL_1)で行われる。この設定では、ポテンショメーター値によりオンとオフの継続時間が変更される。TASSEL_2の設定によりPWMクロックは24MHzになる。この場合、LEDの点滅は認識されない(TA0CCR0の値による)が、LEDの輝度が変わっているように見える。
  • void SetLedDuty(uint16 duty);

    この機能はLEDをPWMのデューティー比に設定する。その効果はタイマー周期に依存する。遅い場合には、LEDはポテンショメーター値に比例して点滅頻度が変わる。速い場合には、LEDは点灯し続けているように見えるが、その輝度はポテンショメーター値により変化する。

  • void EnableADCTimer(void);

    これは第2のタイマーで測定頻度を決定する。

  • void EnableADC();

    シングルショット計測用ADCを設定

  • uint16 ReadADCVal(void);

    ADCの1サンプルを読み込む

プログラム実行

以下のソースコードをコンパイル・ロードし実行するとプログラムが起動する。

ソースコード

ソースコードは以下の通り。テスト済みで IARもしくはCCS利用により実行可能。

--------------------

#include <msp430F5659.h>
#include "F5659Utils.h"

void EnableLedPWM(void);
void EnableADCTimer(void);
void EnableADC();
void SetLedDuty(uint16 duty);
uint16 ReadADCVal(void);

int main(void) {
    WDTCTL = WDTPW + WDTHOLD;               //    Stop WDT
    SetCoreVoltage(VCORE19);                //    Set the core to 1.9V
    SetFLL(24);                             //    Set SMCLK to 24 MHz
    EnableLedPWM();
    SetLedDuty(25);
    EnableADCTimer();
    EnableADC();
    __bis_SR_register(LPM0_bits + GIE);     //    Enter LPM0, enable interrupts
}

void EnableLedPWM(void) {
    P1DIR |= 0x04;                          //    P1.2 output
    P1SEL |= 0x04;                          //    P1.2 as timer output
    TA0CCR0 = 32768-1;                      //    PWM Period
    TA0CCTL1 = OUTMOD_7;                    //    CCR1 reset/set
    TA0CCR1 = 16384;                        //    CCR1 PWM duty cycle
    TA0CTL = TASSEL_1 + MC_1 + TACLR;       //    ACLK, up mode, clear TAR
}

void SetLedDuty(uint16 duty) {
    uint32 val;                             //    Use a 32-bit value so that it does not overflow
    if(duty > 4095) duty = 4095;
    val = TA0CCR0;
    val *= duty;
    val /= 4096;
    TA0CCR1 = (uint16)val;
}

void EnableADCTimer(void) {
  TA1CCTL0 = CCIE;                          // CCR0 interrupt enabled
  TA1CCR0 = 511;                            //    Check ADC every 15.6 ms (64 Hz)
  TA1CTL = TASSEL_1 + MC_1 + TACLR;         // SMCLK, upmode, clear TAR
  P2DIR = 0x01;
}

void EnableADC() {
    ADC12CTL0 = ADC12ON+ADC12SHT0_2;        // Turn on ADC12, set sampling time
    ADC12CTL1 = ADC12SHP;                   // Use sampling timer
    ADC12CTL0 |= ADC12ENC;                  // Enable conversions
}

uint16 ReadADCVal(void) {
    uint16 retval;                          //    Value for debugging purpose
    ADC12CTL0 |= ADC12SC;                   //    Start conversion-software trigger
    while (!(ADC12IFG & BIT0));             //    Wait for the ADC
    retval = ADC12MEM0;                     //    Set breakpoint here to verify value
    return retval;
}

// Timer0 A0 interrupt service routine
#pragma vector=TIMER1_A0_VECTOR
__interrupt void TIMER1_A0_ISR(void) {
    uint16    adcval;
    adcval = ReadADCVal();
    SetLedDuty(adcval);
}

--------------------