目次
前
次
パルス出力試験
ArduinoのデジタルI/Oを利用して、パルス出力試験を
してみました。
次のタイミングチャートで、動作する装置がありました。
手動でトリガーを与えると、パルスを出力すると動いたので
パルス幅が最低どれだけあればよいのかを調べることに。
シリアルでパルス幅を与え、動作確認します。
利用するArduinoは、MakerNanoを選定。
MakerNanoは、GPIOのうち0から12にLEDが接続されているので
動作を目視できるので、今回の用途には最適と判断。
パルス幅は、1msの整数倍として、次のようにシリアル
インタフェースを利用して設定することに。
シリアルインタフェースを使うので、操作を1文字コマンドで
指定します。
コマンドリストを、以下に挙げます。
- ? コマンドリスト一覧表示
- E 指定した時間幅(msの倍数)で、パルスを出力
- M 時間幅を設定
- m 時間幅を表示
各コマンドの処理を定義していきます。
? コマンドリスト一覧表示
コマンドリストを表示するので、関数を使って
まとめてシリアル出力するようにします。
void show_help()
{
Serial.println("? help");
Serial.println("E send pluse");
Serial.println("M set interval count");
Serial.println("m show interval count");
}
E 指定した時間幅(msの倍数)で、パルスを出力
イベント通知フラグを利用し、ステートマシンで
指定した時間幅で、パルスを出力するように関数
を定義すればよいでしょう。
ステートマシンは、次のステートダイアグラムで実現。
ステートマシンを、関数の中に入れます。
void do_pluscode()
{
switch( state ) {
/* wait trigger */
case 0 : state = 0 ;
if ( eflag == ON ) {
state = 1 ;
eflag = OFF ;
}
break ;
/* set interval and set H */
case 1 : state = 2 ;
bcur = millis() + myinterval;
digitalWrite(XLED,ON) ;
break ;
/* delay and set L */
case 2 : state = 2 ;
if ( millis() >= bcur ) {
state = 3 ;
digitalWrite(XLED,OFF) ;
}
break ;
/* return first state */
case 3 : state = 0 ;
break ;
/* others */
default : state = 0 ;
break ;
}
}
Arduinoには、システムタイマーの値を取得する関数millis()が
あるので、現在値に時間間隔に相当する値を加算して、その値を
超えたかで、時間経過を判定。
ステート値で該当状態にあるときに、何をするかを
記述しておけば、機械的にプログラムができます。
ステートマシンを動かすための初期化を担当する
関数を定義しておきます。
void init_pluscode()
{
digitalWrite(XLED,OFF);
pinMode(XLED,OUTPUT);
state = 0 ;
eflag = OFF ;
myinterval = 500 ;
}
パルス出力のピンは、XLEDとしてマクロ定義して
後から変更可能にしておきましょう。
#define XLED 12
ステートマシンを動かすために、イベント通知フラグを
利用しているので、コマンド'E'を与えられたときに
イベント通知フラグをセット。
eflag = ON ;
M 時間幅を設定
時間幅は、変数myintervalに設定するとして、受信
バッファ中の文字列を、整数にして格納することに。
myinterval = atoi( &sbuf[1] );
m 時間幅を表示
数myintervalの値を、表示すればよいので
標準バンドリングされている関数を利用。
Serial.println(myinterval);
ここまでで、シリアルインタフェースを使って動作する
コマンドインタプリタから呼出す処理を定義したので
コマンドインタプリタそのものを定義。
void cmd_handling()
{
/* judge */
if ( uflag == OFF ) return ;
/* clear */
uflag = OFF ;
/* command interpreter */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help(); }
/* event */
if ( cmd == 'E' ) { eflag = ON ; }
/* set counter */
if ( cmd == 'M' ) { myinterval = atoi( &sbuf[1] ); }
/* show counter */
if ( cmd == 'm' ) { Serial.println(myinterval); }
}
コマンドインタプリタを起動するには、受信割込みで
イベント通知フラグを利用すると考えます。
受信割込み処理を定義。
void serialEvent()
{
char ch;
if ( Serial.available() > 0 ) {
/* get 1 character */
ch = Serial.read();
/* store */
*(sbuf+sindex) = ch ;
/* increment */
sindex++ ;
/* judge */
if ( ch == '\r' ) {
sindex = 0 ;
uflag = ON ;
}
}
}
シリアルでコマンドを与えないと、動作しないので
Arduino上のプログラムが動いているかを判断可能
できるように、基板上のLEDを点滅させます。
LED点滅を扱う関数は、以下。
void sys_timer_handling()
{
/* get current system timer */
cur = millis();
/* calculate interval */
sdiff = cur - pre ;
/* judge */
if ( sdiff < SDIFF_MAX ) return ;
/* update */
pre = cur ;
/* impress */
digitalWrite(LEDP,xcnt & ON );
/* update */
xcnt++ ;
}
システムタイマーのカウンタ値を常に入力して
記憶している値の差を計算して、規定値超えと
なっているのかを調べます。
規定値を超えていれば、変数xcntのLSBが1か0かを
取り出して、基板上のLEDに転送。
システムタイマーの値やLED点滅に使う変数の初期化
をしておきます。
void init_sys_timer()
{
pre = millis();
cur = pre ;
xcnt = 0 ;
}
Arduinoのプログラムは、2関数setup()、loop()で
構成するので、これらの関数を定義。
void setup()
{
/* pin value */
digitalWrite( LEDP , OFF );
/* data direction */
pinMode( LEDP , OUTPUT );
/* initialize system timer */
init_sys_timer();
/* Debug */
Serial.begin(9600);
Serial.println("Hello !");
uflag = OFF ;
init_pluscode();
}
void loop()
{
/* timer counter */
sys_timer_handling();
/* command interpreter */
cmd_handling();
/* perform each mode */
do_pluscode();
}
まとめます。
#include <stdio.h>
#include <stdlib.h>
#define OFF 0
#define ON OFF+1
#define LEDP 13
#define XLED 12
#define SDIFF_MAX 500
unsigned long pre ;
unsigned long cur ;
word sdiff ;
byte xcnt ;
unsigned long bcur ;
char sbuf[16];
boolean uflag ;
char cmd ;
byte sindex ;
word myinterval ;
byte state ;
boolean eflag ;
/* function prototype */
void init_sys_timer();
void sys_timer_handling();
void init_pluscode();
void do_pluscode();
void cmd_handling();
void show_help();
void setup()
{
/* pin value */
digitalWrite( LEDP , OFF );
/* data direction */
pinMode( LEDP , OUTPUT );
/* initialize system timer */
init_sys_timer();
/* Debug */
Serial.begin(9600);
Serial.println("Hello !");
uflag = OFF ;
init_pluscode();
}
void loop()
{
/* timer counter */
sys_timer_handling();
/* command interpreter */
cmd_handling();
/* perform each mode */
do_pluscode();
}
void init_sys_timer()
{
pre = millis();
cur = pre ;
xcnt = 0 ;
}
void sys_timer_handling()
{
/* get current system timer */
cur = millis();
/* calculate interval */
sdiff = cur - pre ;
/* judge */
if ( sdiff < SDIFF_MAX ) return ;
/* update */
pre = cur ;
/* impress */
digitalWrite(LEDP,xcnt & ON );
/* update */
xcnt++ ;
}
void init_pluscode()
{
digitalWrite(XLED,OFF);
pinMode(XLED,OUTPUT);
state = 0 ;
eflag = OFF ;
myinterval = 500 ;
}
void do_pluscode()
{
switch( state ) {
/* wait trigger */
case 0 : state = 0 ;
if ( eflag == ON ) {
state = 1 ;
eflag = OFF ;
}
break ;
/* set interval and set H */
case 1 : state = 2 ;
bcur = millis() + myinterval;
digitalWrite(XLED,ON) ;
break ;
/* delay and set L */
case 2 : state = 2 ;
if ( millis() >= bcur ) {
state = 3 ;
digitalWrite(XLED,OFF) ;
}
break ;
/* return first state */
case 3 : state = 0 ;
break ;
/* others */
default : state = 0 ;
break ;
}
}
void cmd_handling()
{
/* judge */
if ( uflag == OFF ) return ;
/* clear */
uflag = OFF ;
/* command interpreter */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help(); }
/* event */
if ( cmd == 'E' ) { eflag = ON ; }
/* set counter */
if ( cmd == 'M' ) { myinterval = atoi( &sbuf[1] ); }
/* show counter */
if ( cmd == 'm' ) { Serial.println(myinterval); }
}
void show_help()
{
Serial.println("? help");
Serial.println("E send pluse");
Serial.println("M set interval count");
Serial.println("m show interval count");
}
/* receive interrupt */
void serialEvent()
{
char ch;
if ( Serial.available() > 0 ) {
/* get 1 character */
ch = Serial.read();
/* store */
*(sbuf+sindex) = ch ;
/* increment */
sindex++ ;
/* judge */
if ( ch == '\r' ) {
sindex = 0 ;
uflag = ON ;
}
}
}
ブレッドボードで、動作実験すると以下。
ブレッドボード上の別のLEDを用意したのは
次の利用から。
大きめのLEDなら、パルス幅分の信号が
出力されていることを、目視しやすい。
目次
前
次