目次
前
次
LEDマトリクス
micro:bitには、5x5のLEDマトリクスがあり
表示器として、面白い動作をさせられます。
LEDマトリクスのエミュレーションをしてみたいと
半田付けました。
top
bottom
回路図は、以下。
動かし方を考えます。
5x5のLEDマトリクスなので、ポートB、ポートCを
利用して、行の点灯パターンをポートBで扱い、列の
指定にはポートCを利用。
OUT_1からOUT_5は、ポートBに接続、OUT_6からOUT_10は
ポートCへ接続します。
制御信号は、正論理で利用。
この仕様で、LEDを扱うコードは、以下にしました。
/* blank */
bport = 0x00 ;
/* display */
if ( tflag == ON ) { bport = *(xpat+state) ; }
/* impress */
PORTB = bport ;
/* scan */
PORTC = 1 << state ;
/* update */
state++ ;
state %= 5 ;
通常は、行に消灯指定のパターンを与えて
列の制御信号を、そのまま出力。
常に動いていて、全LEDが消灯しているように
見えるので、ダイナミックストップと言えます。
パターンは、5バイトの配列xpatに入れ
どの行を扱うのかを変数stateで選択可能
にしておきます。
フリッカが起きないように、行は5msごとに
点灯パターンを変えます。この周期の生成
には、タイマー割込みを活用。
タイマー割込みのイベント通知を入れると
次のコードになります。
if ( eflag == ON ) {
/* clear flag */
eflag = OFF ;
/* blank */
bport = 0x00 ;
/* display */
if ( tflag == ON ) { bport = *(xpat+state) ; }
/* impress */
PORTB = bport ;
/* scan */
PORTC = 1 << state ;
/* update */
state++ ;
state %= 5 ;
}
Arduinoのloopの中に、上のコードを入れると
ダイナミック点灯による、LEDマトリクス表示
が完成。
タイマー割込みは、MsTimer2を利用して
お手軽に対応します。
関係する手続きと関数は、以下。
/* 5ms period */
MsTimer2::set(5,update_trigger);
/* enable */
MsTimer2::start();
void update_trigger()
{
eflag = ON ;
}
点灯パターンを変更したり、確認したいので
コマンドインタプリタを入れて対応します。
コマンドは、以下。
- ? ヘルプ
- G パターン点灯
- g 全LED消灯
- P 1行のパターン設定
- p 現在の各行パターン表示
コマンドは、端末ソフトを利用してPCから
与えるとして、次の仕様にしておきます。
データ転送速度 9600bps
データ長 8ビット
パリティ なし
フロー制御 なし
通信関係仕様を規定したので、必要な関数を定義。
void rs_putchar(char x)
{
Serial.write(x);
}
void rs_puts(char *ptr)
{
while ( *ptr ) {
rs_putchar( *ptr );
ptr++;
}
}
void crlf()
{
rs_putchar('\r');
rs_putchar('\n');
}
シリアル処理で、write関数を多用するとコード
サイズが増えるので、rs_putcharにまとめてます。
これを使って、文字列表示と改行を定義。
文字列処理ができると、コマンドのヘルプを実現
する関数を作成できます。
void show_help()
{
rs_puts("? help") ; crlf();
rs_puts("G enable") ; crlf();
rs_puts("g disable") ; crlf();
rs_puts("P set pattern") ; crlf();
rs_puts("p show pattern") ; crlf();
}
コマンドインタプリタは、受信割込みで
PCからの送信情報を格納し、受信バッファ
に、全データが入ったことをイベント通知
フラグで知らせて貰うようにします。
割込み処理は、次のように定義。
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 ;
}
}
}
イベント通知フラグは、uflagとしておきます。
また、受信バッファは、sbufという名で配列を
用意。
ここまで準備したなら、コマンドインタプリタを
書いていきます。
if ( uflag == ON ) {
/* clear flag */
uflag = OFF ;
/* new line */
crlf() ;
/* get command */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help(); }
if ( cmd == 'G' ) { tflag = ON ; }
if ( cmd == 'g' ) { tflag = OFF; }
if ( cmd == 'P' ) {
/* get index */
j = *(sbuf+1) - '0' ;
/* clear */
tmp = 0 ;
/* get pattern */
for ( i = 0 ; i < 5 ; i++ ) {
tmp <<= 1 ;
tmp |= *(sbuf+2+i) - '0' ;
}
/* store */
*(xpat+j) = tmp ;
}
if ( cmd == 'p' ) {
show_byte( *(xpat+0) ); crlf();
show_byte( *(xpat+1) ); crlf();
show_byte( *(xpat+2) ); crlf();
show_byte( *(xpat+3) ); crlf();
show_byte( *(xpat+4) ); crlf();
}
}
コマンドPでは、行番号を0から4で指定した後に
点灯パターンを2進数で与えるとしました。
コマンドpでは、専用関数で1行のパターンを表示。
このパターン表示は、次のように定義。
void show_byte(char x)
{
char xtmp[6] ;
*(xtmp+5) = '\0' ;
*(xtmp+4) = (x & 1) + '0' ; x >>= 1 ;
*(xtmp+3) = (x & 1) + '0' ; x >>= 1 ;
*(xtmp+2) = (x & 1) + '0' ; x >>= 1 ;
*(xtmp+1) = (x & 1) + '0' ; x >>= 1 ;
*(xtmp+0) = (x & 1) + '0' ;
rs_puts( xtmp );
}
ここまでに定義した内容をまとめると、以下。
/*
apro.ino
Pin assignment
PORTB
PB5 (output) LED
PB4 (output) pattern4
PB3 (output) pattern3
PB2 (output) pattern2
PB1 (output) pattern1
PB0 (output) pattern0
PORTC
PC5 (output)
PC4 (output) select4
PC3 (output) select3
PC2 (output) select2
PC1 (output) select1
PC0 (output) select0
PORTD
PD7 (output)
PD6 (output)
PD5 (output)
PD4 (output)
PD3 (output)
PD2 (output)
PD1 (output)TxD
PD0 (input) RxD
*/
#include <MsTimer2.h>
#define OFF 0
#define ON OFF+1
#define MASK0F 0x0f
#define MASKF0 0xf0
#define MASKFF 0xff
#define MASK7F 0x7f
/* function prototype */
void update_trigger();
void show_help();
void rs_putchar(char x);
void rs_puts(char *ptr);
void crlf();
void show_byte(char x);
/* variables */
boolean tflag ;
boolean eflag ;
boolean uflag ;
byte xpat[5] ;
byte state ;
byte sbuf[16] ;
byte sindex ;
byte cmd ;
byte i ;
byte j ;
byte tmp ;
byte bport ;
void setup()
{
/* initialize serial */
Serial.begin(9600);
sindex = 0 ;
rs_puts("Hello !");
crlf();
/* clear flags */
tflag = OFF ;
eflag = OFF ;
uflag = OFF ;
/* initialize port values */
PORTB = 0x00 ;
PORTC = 0x00 ;
PORTD = 0x00 ;
/* initialize port direction */
DDRB = 0xff ;
DDRC = 0xff ;
DDRD = 0xfe ;
/* variables */
state = 0 ;
*(xpat+0) = 16 ;
*(xpat+1) = 1 ;
*(xpat+2) = 2 ;
*(xpat+3) = 4 ;
*(xpat+4) = 8 ;
/* 5ms period */
MsTimer2::set(5,update_trigger);
/* enable */
MsTimer2::start();
}
void loop()
{
/* command interpreter */
if ( uflag == ON ) {
/* clear flag */
uflag = OFF ;
/* new line */
crlf() ;
/* get command */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help(); }
if ( cmd == 'G' ) { tflag = ON ; }
if ( cmd == 'g' ) { tflag = OFF; }
if ( cmd == 'P' ) {
/* get index */
j = *(sbuf+1) - '0' ;
/* clear */
tmp = 0 ;
/* get pattern */
for ( i = 0 ; i < 5 ; i++ ) {
tmp <<= 1 ;
tmp |= *(sbuf+2+i) - '0' ;
}
/* store */
*(xpat+j) = tmp ;
}
if ( cmd == 'p' ) {
show_byte( *(xpat+0) ); crlf();
show_byte( *(xpat+1) ); crlf();
show_byte( *(xpat+2) ); crlf();
show_byte( *(xpat+3) ); crlf();
show_byte( *(xpat+4) ); crlf();
}
}
/* handling */
if ( eflag == ON ) {
/* clear flag */
eflag = OFF ;
/* blank */
bport = 0x00 ;
/* display */
if ( tflag == ON ) { bport = *(xpat+state) ; }
/* impress */
PORTB = bport ;
/* scan */
PORTC = 1 << state ;
/* update */
state++ ;
state %= 5 ;
}
}
void update_trigger()
{
eflag = ON ;
}
void show_help()
{
rs_puts("? help") ; crlf();
rs_puts("G enable") ; crlf();
rs_puts("g disable") ; crlf();
rs_puts("P set pattern") ; crlf();
rs_puts("p show pattern") ; crlf();
}
void rs_putchar(char x)
{
Serial.write(x);
}
void rs_puts(char *ptr)
{
while ( *ptr ) {
rs_putchar( *ptr );
ptr++;
}
}
void crlf()
{
rs_putchar('\r');
rs_putchar('\n');
}
void show_byte(char x)
{
char xtmp[6] ;
*(xtmp+5) = '\0' ;
*(xtmp+4) = (x & 1) + '0' ; x >>= 1 ;
*(xtmp+3) = (x & 1) + '0' ; x >>= 1 ;
*(xtmp+2) = (x & 1) + '0' ; x >>= 1 ;
*(xtmp+1) = (x & 1) + '0' ; x >>= 1 ;
*(xtmp+0) = (x & 1) + '0' ;
rs_puts( xtmp );
}
/* 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 ;
}
}
}
Arduino基板とLEDマトリクス基板を接続すると
次のようになります。
TeraTermを使って、コマンドインタプリタのチェックを
すると、次のようになります。
コマンドG、gを利用して、ダイナミック点灯で
表示されるのを確認できました。
7と表示されているのが、お分かり頂けるだろうか。
目次
前
次