これまでの記事でご紹介したように、息子ともしくんからの要望により、交通信号機をいくつか作成しています。

トミカ数十台(毎回すごい数出してくるから片付けが大変…)&作った信号機を使って、ともしくんはいつも遊んでいるのですが、先日、
ともしくん作った信号機(普通の信号機と矢印付き信号機)2つ同時に動かして遊びたい!
と言い出しまして…
現在、我が家には信号機を動かすマイコンがArduino UNO R3(実際は互換品のELEGOO UNO R3)1つしかないので、信号機は1つしか動かせません。
別の信号機を動かしたいときは、毎回スケッチの書き換え&信号機の載せ替えを行っています。(結構めんどい)
うーん、どうしたもんか。Arduino UNO R3をもう一台買うとなると結構お金かかるし。
…てか、自作ってできないもんなのかな??そしたら、もっと安くできそうじゃない!?
ということで、自作してみました(笑)ので、その一部始終を紹介したいと思います!
電子工作レベルを上げるために自作してみたい!、マイコンを安く手に入れるために自作してみたい!という方は、ぜひ参考にしてください~^^
必要な部品を購入
Arduino UNO R3を自作するには以下の部品が必要になります。
すべて秋月電子で1000円未満(送料除く)で購入できます。
この値段で自作できるのは安いですよね!。
ATMEGA328P-PU×1個
クリスタル(水晶発振子) 16MHz×1個
積層セラミックコンデンサー 22pF50V±5%2.54mm×2個 ←1パック10個入り
積層セラミックコンデンサー 0.1μF50V X7R 2.54mm×1個 ←1パック10個入り
タクトスイッチ(黒色)×1個
カーボン抵抗(炭素皮膜抵抗) 1/4W10kΩ×1本 ←1パック100個入り(多い…)
↓のちのち、基板化したいので、ICの取り外しができるようにICソケットも購入しました。
丸ピンICソケット (28P)×1個
【追記】
上で紹介したATmega328Pはブートローダ未書き込みっぽいです。
書き込み済みがよい方は以下から購入するのがよいかと思います。


差額40円なので、ブートローダ書き込みが面倒な方はこっちで全然いいかもです。
ピン配置も書かれてますし。。。
ELEGOO UNO R3のICを載せ替え
いきなり、ATmega328Pで回路を組んでスケッチを書き込むと、エラーが発生したときに何が問題かの切り分けが難しくなってしまいます。(あと、一発でエラーが出ずに成功する気がしない…)
なので、問題の切り分けを簡単にするべく、手持ちのELEGOO UNO R3のIC(ATmega328P)だけ取り替えて、試しにスケッチが書き込めるかをやってみました。
ELEGOO UNO R3のATmega328Pは取り外し可能になっています。
自分はマイナスドライバーで、そーっと、ゆっくーり、やさしーく、てこの原理を活用(笑)しながら外しました。
(取り外すと、購入したATmega328Pと区別できなくなりそうなので、マスキングテープでマークを付けました)




ちなみに、IC引き抜き工具があると、ICの足を曲げることもなく安全に取り外せると思います。


↑安いのがいい人


↑費用が高いけど★が高いのがいい人
スケッチを書き込んでみたところエラーが発生!
スケッチ書き込みボタンをぽちっとしたところ、以下のようなエラーが発生。。。
おそらく載せ替えたATmega328Pに問題があると思われます。
(変えたのはATmega328Pだけなので、他に問題がある可能性は低い)
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 9 of 10: not in sync: resp=0xcc
もしや、購入したATmega328Pのブートローダに問題があるのでは?と思い、スケッチ書き込み時のArduinoのLチカ(digital13番ピン下のLマークのオレンジ色のライト)を確認したところ、チカチカしてない!
→ブートローダが正常だと電源供給時にLマークのライトが高速点滅します。
ということで、ブートローダを再書き込みすることにしました。
どうやら間違えてブートローダ未書き込みのATmega328Pを購入してしまったみたいです。
ブートローダを書き込む
事前準備:Arduinoを書き込み装置に変更する
Arduinoを書き込み装置として使用して、購入したATmega328Pにブートローダを書き込みます。
まずは、前の前の章で引っこ抜いたATmega328P(正常に動作するやつ)を元に戻します。
ATmega328Pを差し込む際は向きに気を付けてください。


Arduinoを書き込み装置として使用するために、ArduinoISPのスケッチをまず書き込みます。
「ファイル」→「スケッチ例」→「11.ArduinoISP」→「ArduinoISP」


ArduinoをPCとUSB接続して、ArduinoISPのスケッチを書き込みます。
「書き込み完了」のメッセージが出ればOKです。
ブートローダを書き込む
ブートローダ書き込み用の回路をブレッドボード上に組みます。
ATmega328PをArduino ISPとして使う場合、SPI通信に必要な5つのピン(VCC, GND, SCK, MISO, MOSI, RESET)を書き込み側のArduinoの対応するピンに接続する必要があります。
| 書き込み側のArduino | ATmega328P | |
|---|---|---|
| VCC | 5V | 7番ピン、20番ピン |
| GND | GND | 8番ピン、22番ピン |
| SCK | digital13番ピン | 19番ピン |
| MISO | digital11番ピン | 17番ピン |
| MOSI | digital12番ピン | 18番ピン |
| RESET | digital10番ピン | 1番ピン |
あとは、16MHzの水晶振動子をATmega328Pの9番10番ピンに接続します。
回路はこんな感じです↓




ブレッドボード上のATmega328Pの向き(U字型の切り欠き)は右側です。
回路を組んだところで、ATmega328Pにブートローダを書き込んでいきます。
「ツール」→「ボード」→「Arduino UNO」を選択


「ツール」→「書き込み装置」→「Arduino as ISP」を選択


「ツール」→「ブートローダを書き込む」を実行で、ブートローダが書き込まれます。


「ブートローダの書き込みが完了しました。」の表示が出ればOKです!
試しにLチカしてみる
ブートローダの書き込みが本当に正常に完了しているか、スケッチ例のBlinkを書き込んで動作確認をしてみます。
このまま、Arduinoを書き込み装置として使用して、ATmega328Pにスケッチを書き込みたいと思います。
配線はさきほどブートローダを書き込んだ配線のままで、Blinkのスケッチを書き込みます。
Blinkのスケッチは以下にあります。
「ファイル」→「スケッチ例」→「01.Basics」→「Blink」


「ツール」→「書き込み装置」→「Arduino as ISP」を選択


「スケッチ」→「書き込み装置を使って書き込む」でATmega328Pにスケッチを書き込みます。


エラーが発生することなく、書き込みが完了すれば、書き込み側のArduinoのdegitalピン13番下のLライトが1000msec=1秒ごとに点滅するはずです。
(ATmega328Pの19番ピンがArduinoのdigital13番ピンとつながっているので、ArudinoのLEDがチカチカします。)


代わりに、ATmega328Pの19番ピンとArduinoのdigital13番ピンの接続を外して、ATmega328Pの19番ピンにLEDをつなげると、LEDがチカチカするはずです。
こんな感じ↓




交通信号機をブレッドボード上で動かしてみる
無事、ATmega328Pにスケッチを書き込めるようになったので、本来の目的である信号機のスケッチを書き込みます。
普通の交差点の信号機のスケッチを書き込みたいと思います↓
// Crossroad Signal
// 十字路交差点の車両信号・歩行者信号のプログラム
// Define Pins
// 車両信号機1
#define CAR_SIG1_R 12 // 赤
#define CAR_SIG1_Y 11 // 黄
#define CAR_SIG1_B 10 // 青
// 歩行者信号機1
#define PED_SIG1_R 9 // 赤
#define PED_SIG1_B 8 // 青
// 車両信号機2
#define CAR_SIG2_R 6 // 赤
#define CAR_SIG2_Y 5 // 黄
#define CAR_SIG2_B 4 // 青
// 歩行者信号機2
#define PED_SIG2_R 3 // 赤
#define PED_SIG2_B 2 // 青
#define GREEN_TIME 20000 // 青信号の時間
#define YELLOW_TIME 6000 // 黄信号の時間&歩行者青信号点滅の時間
#define ALL_RED_TIME 6000 // 信号切替の時間(全ての信号が赤の時間)
// 全信号消灯
void all_low(){
// 車両信号機1 消灯
digitalWrite(CAR_SIG1_B, LOW);
digitalWrite(CAR_SIG1_Y, LOW);
digitalWrite(CAR_SIG1_R, LOW);
// 歩行者信号機1 消灯
digitalWrite(PED_SIG1_B, LOW);
digitalWrite(PED_SIG1_R, LOW);
// 車両信号機2 消灯
digitalWrite(CAR_SIG2_B, LOW);
digitalWrite(CAR_SIG2_Y, LOW);
digitalWrite(CAR_SIG2_R, LOW);
// 歩行者信号機2 消灯
digitalWrite(PED_SIG2_B, LOW);
digitalWrite(PED_SIG2_R, LOW);
}
void setup() {
// 車両信号機1 初期化
pinMode(CAR_SIG1_B, OUTPUT);
pinMode(CAR_SIG1_Y, OUTPUT);
pinMode(CAR_SIG1_R, OUTPUT);
// 歩行者信号機1 初期化
pinMode(PED_SIG1_B, OUTPUT);
pinMode(PED_SIG1_R, OUTPUT);
// 車両信号機2 初期化
pinMode(CAR_SIG2_B, OUTPUT);
pinMode(CAR_SIG2_Y, OUTPUT);
pinMode(CAR_SIG2_R, OUTPUT);
// 歩行者信号機2 初期化
pinMode(PED_SIG2_B, OUTPUT);
pinMode(PED_SIG2_R, OUTPUT);
// 全信号 消灯
all_low();
}
void loop() {
//====== 道路1(車両:青/歩行者:青)-道路2(赤) ======//
// 車両信号機1 青 点灯
digitalWrite(CAR_SIG1_B,HIGH);
// 歩行者信号機1 青 点灯
digitalWrite(PED_SIG1_B,HIGH);
// 車両信号機2 赤 点灯
digitalWrite(CAR_SIG2_R,HIGH);
// 歩行者信号機2 赤 点灯
digitalWrite(PED_SIG2_R,HIGH);
delay(GREEN_TIME);
//====== 道路1(車両:青/歩行者:青点滅)-道路2(赤) ======//
// 歩行者信号機1 青 点滅
int i_loop=6;
for( int i=0 ; i<i_loop; i++){
digitalWrite(PED_SIG1_B,HIGH);
delay(YELLOW_TIME/i_loop);
digitalWrite(PED_SIG1_B,LOW);
delay(YELLOW_TIME/i_loop);
}
//====== 道路1(車両:青/歩行者:赤)-道路2(赤) ======//
// 歩行者信号機1 赤 点灯
digitalWrite(PED_SIG1_R,HIGH);
delay(YELLOW_TIME);
//====== 道路1(車両:黄/歩行者:赤)-道路2(赤) ======//
// 車両信号機1 青 消灯
digitalWrite(CAR_SIG1_B,LOW);
// 車両信号機1 黄 点灯
digitalWrite(CAR_SIG1_Y,HIGH);
delay(YELLOW_TIME);
//====== 道路1(赤)-道路2(赤) ======//
// 車両信号機1 黄 消灯
digitalWrite(CAR_SIG1_Y,LOW);
// 車両信号機1 赤 点灯
digitalWrite(CAR_SIG1_R,HIGH);
delay(ALL_RED_TIME);
//====== 道路1(赤)-道路2(車両:青/歩行者:青) ======//
// 車両信号機2 赤 消灯
digitalWrite(CAR_SIG2_R,LOW);
// 車両信号機2 青 点灯
digitalWrite(CAR_SIG2_B,HIGH);
// 歩行者信号機2 赤 消灯
digitalWrite(PED_SIG2_R,LOW);
// 歩行者信号機2 青 点灯
digitalWrite(PED_SIG2_B,HIGH);
delay(GREEN_TIME);
//====== 道路1(赤)-道路2(車両:青/歩行者:青点滅) ======//
// 歩行者信号機2 青 点滅
for(int i=0; i<i_loop; i++) {
digitalWrite(PED_SIG2_B,HIGH);
delay(YELLOW_TIME/i_loop);
digitalWrite(PED_SIG2_B,LOW);
delay(YELLOW_TIME/i_loop);
}
//====== 道路1(赤)-道路2(車両:青/歩行者:赤) ======//
// 歩行者信号機2 赤 点灯
digitalWrite(PED_SIG2_R,HIGH);
delay(YELLOW_TIME);
//====== 道路1(赤)-道路2(車両:黄/歩行者:赤) ======//
// 車両信号機2 青 消灯
digitalWrite(CAR_SIG2_B,LOW);
// 車両信号機2 黄 点灯
digitalWrite(CAR_SIG2_Y,HIGH);
delay(YELLOW_TIME);
//====== 道路1(赤)-道路2(車両:赤/歩行者:赤) ======//
// 車両信号機2 黄 消灯
digitalWrite(CAR_SIG2_Y,LOW);
// 車両信号機2 赤 点灯
digitalWrite(CAR_SIG2_R,HIGH);
delay(ALL_RED_TIME);
//====== 全信号 消灯 ======//
all_low();
}
以前紹介したスケッチ(↓参照)とは、若干異なります。
車両信号機の黄色になるタイミングが少し遅くなっています。


書き込む時の回路ややり方はBlinkスケッチ書き込み時と同じです。
「ツール」→「書き込み装置」→「Arduino as ISP」を選択、
「スケッチ」→「書き込み装置を使って書き込む」でATmega328Pにスケッチを書き込みます。
「書き込み完了」のメッセージが出ればOKです!
あとは、信号機スケッチに合わせて、回路を組みなおします。
ArduinoとATmega328Pのピンマッピングは以下のようになっていますので、それに合わせて回路を組んでいきます。


回路図的にはこんな感じ↓


実物は以前に作った信号機を使っているので、見た目は異なりますが、回路自体は↑と同じです。
電源は単三電池直列三本(4.5V)を使用しています。
写真なので分かりにくいですが信号機が無事光ってます^^
16MHz水晶振動子が5Vで動作する規格なので、若干電圧が低いですが、なんとか動きました。
(ジャンパー線がえらいことになってます(笑))


【追記】
“交通信号機をブレッドボード上で動かしてみる”をやってみる前に、一旦休憩を挟んだ(ArduinoのUSB接続を切って、PCをスリープした)のですが、その後にArduino ISPで書き込みをしたら、書き込みがなかなか終わらない、という現象が発生しました。
Arduino IDEを立ち上げ直して、Arduino ISPの書き込みからやり直したら上手くいきましたので、もし同じような現象で困っている方がいらっしゃったら、試してみてください。
おわりに&その2へ続く
今回の記事では、ATmega328Pを使ったArduinoの自作方法を紹介しました!
初心者の私でしたが、なんとか完成できたので良かったです。
少しは進捗があったので、「これで息子に怒られずに済む!」と安心してます(笑)
(毎日、息子に「ママ、信号機はまだなの?ボク待ってるんだけど。」って言われるので…😭)
ただ、以下の課題がまだ残っていますので、その2に続きます!
・今回作成した自作したArduinoをブレッドボードから基板へ変更する
→作り方がいまいちわかんないので要調査です!(ユニバーサル基板、ピンソケットあればできそうな気がする。)
・電圧が4.5Vと低いので5Vにしたい
→5V出力昇圧DC-DCコンバーターを使って安定して5Vを供給できるようにしたいところです。する、といったところでしょうか?こちらも要調査です!
あと、作ってて思ったのですが、そもそもやりたい事に対してATmega328Pはオーバースペックすぎですよね。
今さら感満載ですが(笑)
のちのち、そのあたりも出来たら色々試してみたいと思います。(Tinyシリーズ?とかが良さそうなのかな…)
最後までお読みいただきありがとうございました^^





コメント