見出し画像

LEDキューブを作ってみる

4x4x4の青色単色のLEDキューブ作りに挑戦です。
マイコンボードと接続してLEDを制御します。

LEDキューブとは

名前の通りLEDで立方体を作ります。
今回は、縦4個、高さ4個、奥行き4個の計64個のLEDで作ります。

回路設計

概要
シフトレジスタを2個使い、LEDを8個づつ計16個を点灯させます。
16個のLEDを1段として、4段構成でLEDキューブを作ります。
4段を高速に切り替えて表示をするダイナミック点灯で実現させます。

使用部品
マイコンボード:秋月電子「AE-RX210」
LED:秋月電子で購入した100本入りの青色LED
シフトレジスタ:TC74HC595AP 2個
トランジスタ:1815YCA25 4個
抵抗:390Ω 16本、2.4KΩ 4本

シフトレジスタICを使う
マイコンからのポートには限りがあるので、ポートから直接出力でLEDを制御するのではなく、シフトレジスターICを使用します。
シフトレジスタICを利用すると、マイコンからシリアル入力→パラレル出力してくれます。パラレル出力した先(8ビット)に、LED8本が出力されるように回路を設計します。

SCKにクロックを入力して、クロック立ち上がりごとにSIからのシリアルデータを、最上位ビットから順に1ビットづつシフトレジスタへ入力していきます。
8ビット分入力したところで、RCKにクロックを入力するとシフトレジスタのデータがストレージレジスタへ転送されて、QA~QHピンから8ビットのパラレルデータとして出力されます。

画像2

SCLR: シフトレジスタをクリアする。通常は「H」。
SCK: シフトレジスタへのクロック信号。
RCK:ストレージレジスタへのクロック信号。
G: 出力の有効無効設定。「L」で出力する。
SI :データのシリアル入力。SCKの立ち上がりでデータを取得(ラッチ)する。

回路図
フリーで使える「BSch3V」という回路図を書くソフトがあったので、このソフトで回路図を作成しました。

画像6

制作開始

最初にLEDキューブのキモであるLED部分の工作です。
まず、LEDを並べてはんだ付けするための治具の作成です。
今回は紙粘土で作成してみました。
1cm間隔でLEDをはめる穴を設けました。

画像3

LEDの足を曲げてLED同士をはんだ付けしていきます。
カソード側は共通で全てアースと接続、アノード側がシフトレジスタICと接続します。

LEDの準備

LEDを治具にセットするとこんな感じです。

LEDセット

この4個のLEDセットを4列作成してはんだ付けすると1段分の作成完了です。

ここでちょっと動作確認してみましょう。
ブレッドボード上で回路を試作して、点灯実験です。
(シフトレジスタICが1つしかないので、8個づつの点灯で確認です。)

動作確認

やった!無事に点灯です。
(後で見返したら抵抗を忘れてますね…)

前回作成したLED回路を3段目まで作成しました。
そして3段目まで重ねてはんだ付けしたまではよかったのですが…
LEDとLEDの隙間が狭すぎて、はんだ付けできない!

というわけ、1cm間隔ではなく、2cm間隔で作り直しです。
左が作り直した2cm間隔のもの、右が1cm間隔のもの。

画像7

制御回路を作成

LED部分を作ったので、次に制御回路を作成です。
シフトレジスターIC2個とLEDの電流制限用の抵抗です。それに、ダイナミック点灯用のトランジスタもはんだ付けします。
テスト的にマイコンボードと接続して、作り直したLEDキューブ1段分を接続して正しく点灯することを確認です。

画像8

点灯確認ができたので、1段ずつ制作したLEDキューブを重ねてはんだ付けします。はんだ付けの際は仮止め用のテープを貼って仮止め後、はんだ付けをします。

画像9

無事4段分LEDキューブをはんだ付け完了。これを基板へはんだ付けします。
最後に配線を行えば完成です。

画像10

最後にマイコンから点灯パターンのデータを出力して完成!

最後にソースコードです。

/***********************************************************************/
/*                                                                     */
/*  FILE        :Test.c                                                */
/*  DATE        :Tue, Oct 06, 2020                                     */
/*  DESCRIPTION :Main Program                                          */
/*  CPU TYPE    :RX210                                                 */
/*                                                                     */
/*  This file is generated by Renesas Project Generator (Ver.4.53).    */
/*  NOTE:THIS IS A TYPICAL EXAMPLE.                                    */
/*                                                                     */
/***********************************************************************/
                 

//#include "typedefine.h"
#ifdef __cplusplus
//#include <ios>                        // Remove the comment when you use ios
//_SINT ios_base::Init::init_cnt;       // Remove the comment when you use ios
#endif
volatile int OneMsTimer01, OneMsTimer02, OneMsTimer03;
char serial_data[8][2];
	
#include "iodefine.h"
void init_mtu(void);
void main(void);
void set_pattern_data(char* data, char serial_data[8][2]);
void output_LED_data(char serial_data[8][2]);
void set_serial_data(char serial_data[8][2]);
void output_parallel_data(void);
void select_floor(int sel);
void timer_func(void);
void wait_msec(int set_msec);
#ifdef __cplusplus
extern "C" {
void abort(void);
}
#endif
/****************************************/
/* 点灯パターンデータ                   */
/****************************************/
char led_pattern[][4][17] =
{
	//1段目               2段目               3段目               4段目 
   //ABCDEFGHABCDEFGH    ABCDEFGHABCDEFGH    ABCDEFGHABCDEFGH    ABCDEFGHABCDEFGH
	{"0001000100010001", "0001000100010001", "0001000100010001", "0001000100010001"},	// 0
	{"0011000100010000", "0011000100010000", "0011000100010000", "0011000100010000"},	// 1
	{"0111000100000000", "0111000100000000", "0111000100000000", "0111000100000000"},	// 2
	{"1111000000000000", "1111000000000000", "1111000000000000", "1111000000000000"},	// 3
	{"1110100010000000", "1110100010000000", "1110100010000000", "1110100010000000"},	// 4
	{"1100100010000000", "1100100010000000", "1100100010000000", "1100100010000000"},	// 5
	{"1000100010001000", "1000100010001000", "1000100010001000", "1000100010001000"},	// 6	
	{"0000100010001100", "0000100010001100", "0000100010001100", "0000100010001100"},	// 7
	{"0000000010001110", "0000000010001110", "0000000010001110", "0000000010001110"},	// 8
	{"0000000000001111", "0000000000001111", "0000000000001111", "0000000000001111"},	// 9
	{"0000000000010111", "0000000000010111", "0000000000010111", "0000000000010111"},	// 10	
	{"0000000100010011", "0000000100010011", "0000000100010011", "0000000100010011"},	// 11
	{"0001000100010001", "0001000100010001", "0001000100010001", "0001000100010001"},	// 12
	{"0000000000000000", "0000000000000000", "0000000000000000", "0000000000000000"},	// 13
	{"1111111111111111", "0000000000000000", "0000000000000000", "0000000000000000"},	// 14
	{"0000000000000000", "1111111111111111", "0000000000000000", "0000000000000000"},	// 15	
	{"0000000000000000", "0000000000000000", "1111111111111111", "0000000000000000"},	// 16
	{"0000000000000000", "0000000000000000", "0000000000000000", "1111111111111111"},	// 17
	{"0000000000000000", "0000000000000000", "0000000000000000", "1111111111111111"},	// 18					
	{"0000000000000000", "0000000000000000", "1111111111111111", "0000000000000000"},	// 19
	{"0000000000000000", "1111111111111111", "0000000000000000", "0000000000000000"},	// 20
	{"1111111111111111", "0000000000000000", "0000000000000000", "0000000000000000"},	// 21
	{"0000000000000000", "0000000000000000", "0000000000000000", "0000000000000000"},	// 22
	
	{"0000000000000000", "0000000000000000", "0000000000000000", "0000000000000000"},	// 23	
	{"0010000010000000", "0000010000000000", "0000000000000000", "0000000000000000"},	// 24
	{"0000000010010000", "0000000001100000"," 0001000000000000", "0000000000000000"},	// 25
	{"0100100010010000", "0010000001100000"," 0001000010000000", "0000000000000000"},	// 26
	{"0100101110010000", "0010010101100000"," 0001000010001000", "0000010000000000"},	// 27
	{"0100101110010101", "0010010101101010"," 0001000010001000", "0010010000000000"},	// 28
	{"1110101110010101", "0010010101101011"," 0001000010001001", "0010010001000000"},	// 29
	{"1110101110011111", "0010110111101011"," 0001010110001001", "0010011001000000"},	// 30
	{"1111101111011111", "0011110111111011"," 0001010110011001", "0010011001001000"},	// 31
	{"1111111111111111", "0011111111111011"," 0001010110011001", "0010011001001000"},	// 32
	{"1111111111111111", "0011111111111111"," 0001010110011101", "0010011001001000"},	// 33
	{"1111111111111111", "1111111111111111"," 0001010110011101", "0010111001001000"},	// 34
	{"1111111111111111", "1111111111111111"," 0011010111011101", "0010111001001000"},	// 35
	{"1111111111111111", "1111111111111111"," 0011010111011111", "0010111001001100"},	// 36
	{"1111111111111111", "1111111111111111"," 0011110111111111", "0010111011001100"},	// 37
	{"1111111111111111", "1111111111111111"," 1011111111111111", "0010111011001100"},	// 38
	{"1111111111111111", "1111111111111111"," 1111111111111111", "0010111011011100"},	// 39
	{"1111111111111111", "1111111111111111"," 1111111111111111", "0011111011011101"},	// 40
	{"1111111111111111", "1111111111111111"," 1111111111111111", "1011111111011111"},	// 41
	{"1111111111111111", "1111111111111111"," 1111111111111111", "1111111111111111"},	// 42
	{"1111111111111111", "1111111111111111"," 1111111111111111", "1111111111111111"},	// 43	
	{"1111111111111111", "1111111111111111"," 1111111111111111", "1011111111011111"},	// 44
	{"1111111111111111", "1111111111111111"," 1111111111111111", "0011111011011101"},	// 45
	{"1111111111111111", "1111111111111111"," 1111111111111111", "0010111011011100"},	// 46
	{"1111111111111111", "1111111111111111"," 1011111111111111", "0010111011001100"},	// 47
	{"1111111111111111", "1111111111111111"," 0011110111111111", "0010111011001100"},	// 48
	{"1111111111111111", "1111111111111111"," 0011010111011111", "0010111001001100"},	// 49
	{"1111111111111111", "1111111111111111"," 0011010111011101", "0010111001001000"},	// 50
	{"1111111111111111", "1111111111111111"," 0001010110011101", "0010111001001000"},	// 51
	{"1111111111111111", "0011111111111111"," 0001010110011101", "0010011001001000"},	// 52
	{"1111111111111111", "0011111111111011"," 0001010110011001", "0010011001001000"},	// 53
	{"1111101111011111", "0011110111111011"," 0001010110011001", "0010011001001000"},	// 54
	{"1110101110011111", "0010110111101011"," 0001010110001001", "0010011001000000"},	// 55
	{"1110101110010101", "0010010101101011"," 0001000010001001", "0010010001000000"},	// 56
	{"0100101110010101", "0010010101101010"," 0001000010001000", "0010010000000000"},	// 57
	{"0100101110010000", "0010010101100000"," 0001000010001000", "0000010000000000"},	// 58
	{"0100100010010000", "0010000001100000"," 0001000010000000", "0000000000000000"},	// 59
	{"0000000010010000", "0000000001100000"," 0001000000000000", "0000000000000000"},	// 60
	{"0010000010000000", "0000010000000000", "0000000000000000", "0000000000000000"},	// 61
	{"0000000000000000", "0000000000000000", "0000000000000000", "0000000000000000"},	// 62
	
	{"0000000000000000", "0000000000000000", "0000000000000000", "0000000000000000"},	// 63
	{"0000000000000000", "0000000000000000", "0000000000000000", "0000000000000000"},	// 64
	{"0000000000000000", "0000000000000000", "0000000000000000", "0000000000000000"},	// 65				
};
/****************************************/
/* タイマー(MTU0)の初期化               */
/****************************************/
void init_mtu(void)
{
	// 割り込み優先順位を最高にする P309、P327
	ICU.IPR[114].BYTE = 0x0F;	// MTU0のTGIA割り込み
	
	// 割り込み要求許可設定 P308、P325
	ICU.IER[3].BYTE = 0x10;
	// 割り込み要求許可設定 P308、P327
	ICU.IER[0x0E].BIT.IEN2 = 1;	// MTU0のTGIAの割り込み要求許可
	// タイマーの設定の全体はP619を参照
 
	// MTU0のTGRAのコンペアマッチ(P569)
	// 立ち上がりエッジでカウント
	// 内部クロック64分周(PCLKB/64) = 20000000 / 64 = 312500Hz
	MTU0.TCR.BYTE = 0x23;
	
	// ノーマルモードで動作(P572)
	// MTU0のTGRAとTGRCレジスタは通常動作
	MTU0.TMDR.BYTE = 0x00;
	
	// MTU0のMTIOC0B、MTIOC0A端子の出力禁止(P574)
	MTU0.TIORH.BYTE = 0x00;
	
	// MTU0のTGIAの割り込み許可(P586)
	MTU0.TIER.BYTE = 0x01;
	// MTU0のTGRにコンペアマッチする値を設定
	// カウントクロック = 312500Hz = 周期は0.0000032秒 = 31(0x001F) * 0.0000032秒 = 0.0000992秒 = 1m秒
	MTU0.TGRA = 0x001F;
	// MTU0のタイマカウンタの設定(P594)
	MTU0.TCNT = 0x0000;
		
	// MTU0のTCNTのカウント動作開始(P595)
	MTU.TSTR.BYTE = 0x01;	
}
/****************************************/
/* main関数                             */
/****************************************/
void main(void)
{
	int pat = 0, sel = 0;
	
	OneMsTimer01 = -1;
	OneMsTimer02 = -1;
	OneMsTimer03 = -1;
			
	// クロックソース選択の保護解除
	SYSTEM.PRCR.WORD = 0x0A50B;
	
	// クロックソースをメインクロック(20MHz)に設定(P203)
	SYSTEM.SCKCR3.WORD = 0x0200;
	
	// 周辺モジュールクロックB(PCLKB)とメインクロックの分周比を64分周に設定(P200)
	SYSTEM.SCKCR.LONG = 0x00000000;
	
	// メインクロック発振器動作設定(P208)
	SYSTEM.MOSCCR.BYTE = 0x00;
	// MTUモジュールストップ状態解除(P247)	
	SYSTEM.MSTPCRA.BIT.MSTPA9 = 0;
		
	// クロックソース選択の保護
	SYSTEM.PRCR.WORD = 0x0A500;
	// MTU0の初期化
	init_mtu();
		
	// ポートを汎用IOとして設定(P508)
	PORT1.PMR.BYTE = 0x00;
	PORT3.PMR.BYTE = 0x00;
	PORTH.PMR.BYTE = 0x00;
	PORTC.PMR.BYTE = 0x00;
			
	// ポートの出力に設定(P505)
	PORT1.PDR.BYTE = 0xFF;	// P17~P10
	PORT3.PDR.BYTE = 0x1F;	// P34~P30
	PORTH.PDR.BYTE = 0x0F;	// PH3~PH0
	PORTC.PDR.BYTE = 0x0F;	// PC3~PC0

	// SCLRの設定
	PORTH.PODR.BIT.B3 = 1;
	
	// Gの設定
	PORT3.PODR.BIT.B4 = 0;
	
	// クロック出力の初期化
	PORTH.PODR.BIT.B1 = 0;  // SCK
	PORTH.PODR.BIT.B2 = 0;	// RCK
	// 出力用クロック信号の初期化
	PORTH.PODR.BIT.B0 = 0;  // SI(CHIP 1)
	PORT3.PODR.BIT.B3 = 0;  // SI(CHIP 2)

	while(1)
	{
		if(pat++ > 65)
		{
			pat = 0;	
		}  				
		while(1)
		{
			// 段数を切り替えながらダイナミック点灯
			select_floor(sel);		
	
			if(sel++ > 3)
			{
				sel = 0;
				break;
			}
				
			set_pattern_data(led_pattern[pat][sel], serial_data);
			
			output_LED_data(serial_data);
		
			// ダイナミック点灯の周期	
			wait_msec(5);
		}
		
		wait_msec(500);
	}
}
/****************************************/
/* 点灯パターンを設定                   */
/****************************************/
void set_pattern_data(char* data, char serial_data[8][2])
{
	int fig = 0, count = 0;
	
	// CHIP2のデータセット
	for(count = 7; count >= 0; count--)
	{
		if(data[fig++] == '1')
		{
			serial_data[count][1] = 1;
		}
		else
		{
			serial_data[count][1] = 0;
		}
	}
	// CHIP1のデータセット
	for(count = 7; count >= 0; count--)
	{
		if(data[fig++] == '1')
		{
			serial_data[count][0] = 1;
		}
		else
		{
			serial_data[count][0] = 0;
		}
	}
}
/****************************************/
/* LEDへデータを出力して発光させる      */
/****************************************/
void output_LED_data(char serial_data[8][2])
{
	set_serial_data(serial_data);
	output_parallel_data();	
}
/****************************************/
/* シリアルデータをシフトレジスタへ入力 */
/****************************************/
void set_serial_data(char serial_data[8][2])
{
	int bit_count = 0;
		
	// シフトレジスタへのクロック信号生成						
	while(bit_count < 8)
	{
		// 1msec周期用のウェイト
		wait_msec(1);
		
		if(PORTH.PODR.BIT.B1 == 0)
		{
			// CHIP1 1ビットずつのシリアルデータ出力
			PORTH.PODR.BIT.B0 = serial_data[bit_count][0];
				
			// CHIP2 1ビットずつのシリアルデータ出力
			PORT3.PODR.BIT.B3 = serial_data[bit_count][1];
							
			// クロック信号立上がり
			PORTH.PODR.BIT.B1 = 1;
				
			bit_count++;
		}
		else
		{
			// クロック信号立下がり
			PORTH.PODR.BIT.B1 = 0;
		}
	}
}
/************************************************/
/* シフトレジスタに入力したデータをパラレル出力 */
/************************************************/
void output_parallel_data(void)
{		
	// ストレージレジスタへのクロック信号生成		
	wait_msec(1);
		
	PORTH.PODR.BIT.B2 = 1;
	wait_msec(1);
	
	PORTH.PODR.BIT.B2 = 0;	
}
/************************************************/
/* LEDキューブの発光させたい段数を指定          */
/************************************************/
void select_floor(int sel)
{
	PORTC.PODR.BIT.B0 = 0;
	PORTC.PODR.BIT.B1 = 0;
	PORTC.PODR.BIT.B2 = 0;
	PORTC.PODR.BIT.B3 = 0;
		
	switch(sel)
	{
	case 0:
		PORTC.PODR.BIT.B0 = 1;
		break;
	case 1:
		PORTC.PODR.BIT.B1 = 1;
		break;	
				
	case 2:
		PORTC.PODR.BIT.B2 = 1;
		break;
	case 3:
		PORTC.PODR.BIT.B3 = 1;
		break;								
	}
}
/************************************************/
/* タイマーカウンター                           */
/************************************************/
void timer_func(void)
{
	if(OneMsTimer01 >= 0)	OneMsTimer01++;
	if(OneMsTimer02 >= 0)	OneMsTimer02++;
	if(OneMsTimer03 >= 0)	OneMsTimer03++;
}
/************************************************/
/* 指定秒数ウエイトする                         */
/************************************************/
void wait_msec(int set_msec)
{
	OneMsTimer01 = 0;
			
	while(OneMsTimer01 < set_msec)
		;
		
	OneMsTimer01 = -1;		
}
	
#ifdef __cplusplus
void abort(void)
{
}
#endif

この記事が気に入ったらサポートをしてみませんか?