google-site-verification: google3bd66dd162ef54c7.html

Arduinoで豪華にLチカをコイン電池で動かす

 一つ前の記事に書いたArduinoで17個のLEDを自在に点滅させる回路のプログラムを改良し、消費電流を大幅に減らしました。狙いは電池で長時間動かすことです。

 消費電流を減らすためにやらないといけないことは二つあります。

 第一は、CPUのATmega329Pの単独動作です。というのは、Arduino UNOの状態ではUSBのインターフェイス回路が同居していてこれがかなりの電流を消費します。つまり、いくらCPUを省エネ化しても、UNOの基板の状態では消費電流はさほど減りません。

 第二は、CPUをスリープ状態に入れて消費電流を減らすことです。これについては後で触れることにします。

▼Atmega328Pの単独動作
ブレッドボードでLチカ
 Arduino UNOでスケッチを書いたCPUを引っこ抜いて使っています。電源はコイン電池(CR2032)です。

▼回路図(クリックで別窓に拡大)
ATmega328Pで豪華なLチカの回路図
 コイン電池だけで動かないことはないですが、LEDの明るさが不足するし、ブラウンアウトでリセットがかかる恐れがある(たぶん2.7V以下)のでDC-DCコンバーター(秋月のM-03451)で5Vに昇圧しています。

 DC-DCコンバーターは軽負荷時には効率が悪くなるイメージがありました。でもこのDC-DCコンは動作モードが負荷の重さで自動的に変わり、無負荷では15μAくらいしか電流を消費しないので、電池駆動の物にも安心して使うことが出来ます。

 ちなみに消費電流はLEDの表示パターンによって変わりますが、電池出口では通常は0.4mA程度、LEDが全部点灯した場合は2.4mAでした。CR2032の容量は200mAhくらいあるので、連続100時間以上は動かすことが出来そうです。
 (参考:5V側の消費電流は0.15~1.1mA程度)

▼プログラム
 普通にプログラムするとCPUは10mA以上の電流を消費してしまうので、コイン電池で長時間動かすことは難しいです。こういう場合の常套手段はCPUをスリープ状態に入れて不要な電力消費を抑えることです。やり方はいろいろありますが、ここでは以前作ったdelayWDTという関数を使ってみました。
 delayWDT関数はCPUのほとんどの機能を止めてスリープさせるので、この時の消費電流はごく僅か(28μA)で済みます。

/* 簡単で豪華なLチカのデモ
* CPUのプルアップ抵抗を使って17個のLEDを使ってLチカ
* delayWDT関数を使って消費電流を削減
* 2015/11/14 ラジオペンチ http://radiopench.blog96.fc2.com/
*/

#include <avr/sleep.h> // スリープモードを使用
#include <avr/wdt.h> // ウォッチドッグタイマーを使用

unsigned long data = 0;
int n;

void setup() {
} // pinModeを指定していないので全部inputになる

void loop() { // メインループ
rotate(5); // 順送り点灯
x_rotate(3); // 順逆同時送り点灯
wave(3); // 波のように表示
parapara(50); // ランダム点灯
}

void rotate( int count) { // 順送り点灯
for (int i = 1; i <= count; i++) {
data = 0x10000; // タネを仕込む
for (n = 0; n <= 17; n++) {
led(data); // ビットパターンを表示
data = data >> 1; // 左にシフト
delayWDT(1); // 32msスリープ
}
}
}

void x_rotate( int count) { // 順・逆送り表示
unsigned long a, b;
for (int i = 1; i <= count; i++) {
a = 0x00001; // 下側のタネ
b = 0x10000; // 上側のタネ
for (n = 0; n <= 17; n++) {
data = a | b; // 上下のタネを合成して、
led(data); // 表示
a = a << 1;
b = b >> 1;
delayWDT(2); // 64ms
}
}
}

void wave(int count) { // 波のように表示
for (int i = 1; i <= count; i++) {
for (n = 0; n <= 16; n++) {
data = data | 0x01; // 右端に1ビット追加
led(data);
data = data << 1; // 左にシフト
delayWDT(2); // 64ms
}
for (n = 0; n <= 16; n++) {
data = data & 0x1FFFE; // 右端のビットを消す
led(data);
data = data << 1; // 左にシフト
delayWDT(2); // 64ms
}
}
}

void parapara( int count) { // ランダム点灯
for (int i = 1; i <= count; i++) {
data = random(0, 0x20000); // 0から0x1FFFFまでの乱数発生
led(data);
delayWDT(3); // 128ms
}
}

void led(unsigned long x) { // LED点灯ルーチン
/* 引数に対応するビットのLEDを点灯。(プルアップ抵抗で点灯させる)
* データーは17ビット、ポートとの対応は下記
* data x xxxx xxxx xxxx xxxx
* PORTD 76 5432
* PORTB 432 10
* PORTC 5 4321 0
* digital 0, 1, 13はブートローダーと干渉するので使わない。
*/
byte d;
x = x & 0x1FFFF; // 変な値を排除

// 下位6ビットを digital 2-7 に出力 (0,1はTX,RXなので使わない)
d = (x << 2) & B11111100;
PORTD = d;

// 6ビット目から5ビットを digital 8-12に出力(13は使わない)
d = (x >> 6) & B00011111;
PORTB = d;

// 11ビット目から6ビットを analog0-5(digital 14-19)に出力
d = (x >> 11) & B00111111;
PORTC = d;
}

void delayWDT(unsigned long t) { // パワーダウンモードでdelayを実行
delayWDT_setup(t); // ウォッチドッグタイマー割り込み条件設定
ADCSRA &= ~(1 << ADEN); // ADENビットをクリアしてADCを停止(120μA節約)
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // パワーダウンモード
sleep_enable();
sleep_mode(); // ここでスリープに入る
sleep_disable(); // WDTがタイムアップでここから動作再開
ADCSRA |= (1 << ADEN); // ADCの電源をON (|=が!=になっていたバグを修正2014/11/17)
}

void delayWDT_setup(unsigned int ii) { // ウォッチドッグタイマーをセット。
// 引数はWDTCSRにセットするWDP0-WDP3の値。設定値と動作時間は概略下記
// 0=16ms, 1=32ms, 2=64ms, 3=128ms, 4=250ms, 5=500ms
// 6=1sec, 7=2sec, 8=4sec, 9=8sec
byte bb;
if (ii > 9 ) { // 変な値を排除
ii = 9;
}
bb = ii & 7; // 下位3ビットをbbに
if (ii > 7) { // 7以上(7.8,9)なら
bb |= (1 << 5); // bbの5ビット目(WDP3)を1にする
}
bb |= ( 1 << WDCE );

MCUSR &= ~(1 << WDRF); // MCU Status Reg. Watchdog Reset Flag ->0
// start timed sequence
WDTCSR |= (1 << WDCE) | (1 << WDE); // ウォッチドッグ変更許可(WDCEは4サイクルで自動リセット)
// set new watchdog timeout value
WDTCSR = bb; // 制御レジスタを設定
WDTCSR |= _BV(WDIE);
}

ISR(WDT_vect) { // WDTがタイムアップした時に実行される処理
// wdt_cycle++; // 必要ならコメントアウトを外す
}

 ちょっと長いプログラムになっていますが、興味のある方は内容を追いかけてみてください。

 なお、delayWDT関数はウォッチドッグタイマー割り込みを使っており、このタイマーはCR発信器で動いています。つまり水晶のように正確な周波数(タイミング)では動かないのでご注意下さい。
関連記事

コメントの投稿

管理者にだけ表示を許可する

実用的な事例を感謝します

ラジオペンチさんの記事は実用的な事例付きなのでとてもありがたいです。
又、下間さんの記事をシミュレーションしてみるなど広範な技術力にも感心しきりです。

今回のArduinoをCR2032で長時間動かす豪華版Lチカはそのまま組める形なのでとても感謝です。
CR2032は1mA程度で使う分には電力を無駄なく利用できるようです。

「CR2032ってどんな電池?」
http://rbs.ta36.com/?p=20398
記事中の「電力量の比較」グラフを抜粋
http://rbs.ta36.com/wp-content/uploads/1365996727_3db07c27fcc95b21d3499a36c36835e2cd436683.png

RGB-LEDを利用すればカラフルなパターン作製を検討できそうで妄想が膨らみます。

re:実用的な事例を感謝します

mytoshiさん、今晩は。

CR2032電力量の記事の情報ありがとうございます。
電流増やすとによって取り出せる容量がこんなに少なくなるとは、知りませんでした。

LR44のデータもご参考まで

追記:小型LEDライトでよく使われるLR44では下記のようになるらしいです。
http://jisaku.155cm.com/src/1366266599_d3e8d4d8ba056b7dd0ed4f37849ab9cadad66ce5.png

電流を多くしてもCR2032ほどには低下していないので、CR2032の内部抵抗の大きさを改めて実感できます。
実際にLR44x3で駆動するLEDライトの方が長い時間明るく照らすことが出来ているので納得できます。

re:LR44のデータもご参考まで

なるほど、電流が大きいと取り出せるエネルギーは減りますが、CR2032みたいに激しい落ち込みは無いんですね。

リチウム電池というと内部抵抗が低そうなイメージがありましたが、コイン電池はそうじゃないんですね。端子電圧も違うので名前だけで一緒くたに考えてはだめなんでしょうね。
カレンダー
04 | 2017/05 | 06
- 1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31 - - -
プロフィール

ラジオペンチ

Author:ラジオペンチ
電子工作を中心としたブログです。たまに近所(東京都稲城市)の話題など。60過ぎて視力や器用さの衰えを感じつつ日々挑戦!
コメントを入れる時にメールアドレスの記入は不要です。なお、非公開コメントは受け付けていません。

記事が気に入ったらクリックを!
最新記事
カテゴリ
最新コメント
リンク
FC2カウンター
検索フォーム
月別アーカイブ
RSSリンクの表示
QRコード
QRコード