="LPC1114 デバッガから圧電スピーカを制御しよう

  NXPセミコンダクタ社LPCXpresso 基板は,開発環境からデータを入出力して,タイマの制御を行わせることもできます.

タイマ・モジュールを制御する仕組み

 コンソールを使用した入出力の最後に紹介するのは,開発環境のコンソール・ビューからコマンドを入力して,タイマ・モジュールの制御を行うアプリケーションです.

タイマを制御する仕組み

 ここでは,16ビット・タイマの一つを使用して圧電スピーカを鳴らしています.1760Hz の周期で PIO0_8 (CT16B0_MAT0) 端子を反転させているので,発振周波数は 880Hz になります.

 タイマの ON/OFF を決めているのは,メイン・ルーチンです.コンソール・ビューからの入力をソフトウェアが受け取り,解析して,タイマの動作を決めています.

ヘッダ部分

 それでは,順にソフトウェアを解説していきます.

/*
===============================================================
 Name        : main.c
 Author      : noritan
 Version     :
 Copyright   : Copyright (C) 2010 noritan.org
 Description : main definition
===============================================================
*/

#ifdef __USE_CMSIS
#include "LPC11xx.h"
#endif

#include <stdio.h>
#include <string.h>

 ヘッダ部分の宣言は,インタプリタのプログラムそのままです.このアプリケーションでは,構文解析を行っていないので,大域変数は宣言していません.

タイマの初期化ルーチン
/*
-------------------------------------------------------
   void TMR16B0_init() :
     Initialize the timer TMR16B0.
     System clock is provided to the module.
-------------------------------------------------------
*/
void TMR16B0_init(void) {
    // Enable clock for CT16B0 module
    LPC_SYSCON->SYSAHBCLKCTRL |= (1UL << 7);
}

 TMR16B0_init() 関数は, TMR16B0 モジュールの初期化を行います.リセット直後, TMR16B0 モジュールには,クロックが供給されていません. SYSAHBCLKCTRL レジスタの7ビット目をセットして,このモジュールにクロックを供給します.

 それぞれのモジュールのクロックをイネーブルにするビットがどこにあるかは,ユーザマニュアルに記述があります.

タイマの周期を設定する関数
/*
-------------------------------------------------------
   void TMR16B0_base() :
     Set the base timer period of the TMR16B0 module.
     Match register #3 (MR3) is used to specify the
     time interval.

   uint32_t interval
     A time period set to the MR3 register.
     Only 16-bit value is effective.  No overflow
     checked.
-------------------------------------------------------
*/
void TMR16B0_base(uint32_t interval) {
    // Set time period of the timer.
    LPC_TMR16B0->MR3 = interval;
    // Reset timer with MATCH3 events.
    LPC_TMR16B0->MCR &= ~(7UL << 9);
    LPC_TMR16B0->MCR |=  (2UL << 9);
}

 TMR16B0_base() 関数では,タイマの周期を設定しています. LPC1114 の16ビット・タイマには,四つの一致レジスタ(Match Register : MR)が存在し,どの一致イベントでもカウンタをリセットすることができます.ここでは, MATCH3 イベントでカウンタをリセットする設定にして, MR3 レジスタで周期を決定しています.タイマの詳しい使い方については,別途,追求します.

MATCH0イベント出力設定関数

/*
-------------------------------------------------------
   void TMR16B0_MAT0_init() :
     Initialize the External Match output port.

   uint32_t mode
     A mode of the external match behavior specified
     for the MATCH0 events.
-------------------------------------------------------
*/
void TMR16B0_MAT0_init(uint32_t mode) {
    // Select CT16B0_MAT0 function to the port.
    LPC_IOCON->PIO0_8 &= ~7UL;
    LPC_IOCON->PIO0_8 |=  2UL;
    // Specify the external match behavior.
    LPC_TMR16B0->EMR  &= ~(3UL  << 4);
    LPC_TMR16B0->EMR  |=  (mode << 4);
}

 TMR16B0_MAT0_init() 関数では, MATCH0 イベントが発生したときに CT16B0_MAT0 出力端子にどのような振る舞いをさせるかを指定します. MATCH0 イベントの一致レジスタ(MR0)は,リセットされたまま使用するため,ゼロになっています.このため,タイマが周期的にリセットされるタイミングで, MATCH0 イベントも周期的に発生します.

 ここで,設定することのできる振る舞いは,セット・リセット・トグルの三種類です.今回のアプリケーションの場合には,トグルを選択して,タイマ周期の2倍の周期で矩形波を出力します.

 リセット後は, CT16B0_MAT0 端子は,汎用I/Oポート PIO0_8 として動作します.この関数では,ポートをタイマ出力として設定する役割ももっています.

タイマ制御関数

/*
-------------------------------------------------------
   void TMR16B0_command() :
     Control the TMR16B0 module.

   uint32_t command
     A command specified for the TMR16B0 module.
     0: Suspend the timer.
     1: Start/Continue the timer.
     2: Reset the timer.
-------------------------------------------------------
*/
void TMR16B0_command(uint32_t command) {
    LPC_TMR16B0->TCR = command;
}

 TMR16B0_command() 関数は,タイマの動作を決定するために,コマンドを送ります.ここで与えるコマンドは,主に,停止(0),開始(1),リセット(2)の三種類です.このアプリケーションでは,これらを使い分けて,圧電スピーカを制御しています.

インタプリタ関数

/*
-------------------------------------------------------
   int interpret() :
     Parse a command line provided as a string.

   const char *line
     A command line to be parsed.

   Return value
     0: a next command is expected.
     1: a command to terminate parsing is detected.
-------------------------------------------------------
*/
int interpret(const char *line) {
    // Escape from the program
    if (strncmp(line, "bye", 3) == 0) {
        fputs("Good bye.\n", stdout);
        TMR16B0_command(0);     // Stop Timer
        return 1;
    }
    // Turn on BEEP
    if (strncmp(line, "on", 2) == 0) {
        fputs("Turn on.\n", stdout);
        TMR16B0_command(1);     // Start Timer
        return 0;
    }
    // Turn off BEEP
    if (strncmp(line, "off", 3) == 0) {
        fputs("Turn off.\n", stdout);
        TMR16B0_command(2);     // Reset Timer
        return 0;
    }
    // Unknown command
    fputs("What ?\n", stdout);
    return 0;
}

 すっかり,見慣れた感のあるインタプリタ関数です.ほとんど LED を制御していたインタプリタと同じで, LED を ON/OFF するかわりに,タイマを制御しています.

メイン関数

/*
-------------------------------------------------------
   int main() :
     Main routine.
-------------------------------------------------------
*/
int main(void) {
    char    line[64];   // Line buffer.
    int     done;       // Flag indicating a process done.

    // Initialize Timer output
    TMR16B0_init();
    TMR16B0_base((SystemCoreClock/LPC_SYSCON->SYSAHBCLKDIV)/1760 - 1);
    TMR16B0_MAT0_init(3);   // Toggle on match

    // Show message
    fputs("HELLO WORLD\n", stdout);

    do {
        // Get a line
        fgets(line, sizeof line, stdin);

        // Interpret
        done = interpret(line);
    } while (!done);

    // Infinite loop.
    while (1) {
    }
    return 0;
}

 メイン関数の構成も LED を制御していたときと同じです.異なっているのは, LED が接続されている汎用ポートの初期設定が,タイマの初期設定に変更されたことです.

圧電スピーカをつなごう

 アプリケーションができあがりましたので,ハードウェアを用意します.このアプリケーションでは, CT16B0_MAT0 端子から矩形波を発生させますが, LPCXpresso 基板のコネクタには,そういった名前の信号は出てきていません.

LPCXpresso 基板に圧電スピーカをつなぐ

 被評価マイコン基板上では, CT16B0_MAT0 信号は, J6 コネクタの6番端子である, "MISO" と名前の付いた端子に出てきます.この端子と "GND" 端子から配線を引き出して,それぞれ 1kΩ の抵抗を介して圧電スピーカに接続します.これで,準備ができました.

実行しよう

 プログラムを書き込んだら,実行させます.

 コンソールから入力されたコマンドに従って,圧電スピーカからの音が ON/OFF されるのがわかります.コマンドを入力してから,実際に音が反応するまで,少し時間がかかりますが,これは,デバッガを通してコマンドが伝達されるまでの遅延です.

コンソール入力には,重要な制約がある

 コンソールからコマンドを入力して,マイコンが制御する世界に介入する.この構成は,非常に有意義に使用できると思っていたのですが,一つだけ重要な制約があることがわかっています.コンソールからの入力を待っているあいだ, CPU の処理がとまってしまうのです.

 この例で紹介したようにタイマというハードウェアが自律的に動作している場合には,音を出したり,止めたりすることができます.しかし,同じ動作でも割り込みを使って圧電スピーカを駆動している場合には,うまく働きません.コンソール入力を待つ間, CPU がとまってしまい,割り込みさえ発生しないので,音を発生させることができないのです.

 CPU による制御を止めることなく,コンソールから制御パラメータを変更してやろうと考えていたのですが,コンソールを使用する方法では,うまくいかないようです.ハードウェアの追加が必要になりますが, UART モジュールを使用して制御する方法で,考えていきたいと思います.

参考文献
LPC111x user manual (UM10398)
LPC111x シリーズ・マイコンのユーザ・マニュアルです.暫定版ということで,記事執筆時点では頻繁に更新されています.この4か月間に,すでに3回更新されました.
LPC111x data sheet
LPC111x シリーズ・マイコンのデータ・シートです.ユーザ・マニュアルには書かれていない,電気的な特性に関する具体的な数値が記述されています.暫定版ということで,記事執筆時点では頻繁に更新されています.この4ヶ月間に,すでに3回更新されました.
LPCXpresso LPC1114 Development Board Schematic
LPCXpresso 基板の回路図です. CT16B0_MAT0 端子が,コネクタのどの端子から引き出されているかは,この回路図を見て判断します.
田中範明(noritan.org)


トラックバック(0)

このブログ記事を参照しているブログ一覧: LPCXpresso で HELLO WORLD (6)

このブログ記事に対するトラックバックURL: http://www.eleki-jack.com/mt/mt-tb.cgi/4131





カテゴリ


Copyright (C) 2006-2015 CQ Publishing Co.,Ltd. All Rights Reserved.