google-site-verification: google3bd66dd162ef54c7.html

Arduinoを省エネで動かす実験

 Arduinoで電源電圧やクロック周波数を下げて動かす環境が出来たので、以前からやってみたかった実験をやりました。

 まず背景から説明すると、
 
 ArduinoのCPUの消費電力を減らす方法として、以前delayWDT関数を作りました。これはパワーダウンモードでスリープさせて、ウォッチドッグタイマーを使って目覚めるという動作を行います。これを使うとスリープ中の消費電流を劇的に(28μA)下げることが出来ます。でも、ウォッチドッグタイマーはCRオシレーターで動いているので時間精度が悪いという難点があります。

 正確な時刻を知るにはRTC(リアルタイム クロック)を使うのが常道で、これならCPUの電源を切っても時刻を刻み続けているので、データーロガーを作る場合などに便利です。またRTCからは割込みなどに使える信号が出ているので、これを使ってスリープしているCPUを目覚めさせることが出来ます。つまりRTCを使えばdelayWDT関数の問題点が解決出来るはずです。

 ということで実際にやってみました。ある程度データーロガーに近い状態で動かしたいので、I2Cの小型キャラクタ液晶も同時に動かすことにしました。スリープから復帰した時に、I2Cが問題なく動くのか確認したかった、という理由もあります。

▼回路図
回路図
 全部3.3Vで動かしているのですっきりした回路になりました。RTCのPin3(INT)の信号でCPUに外部割込みを掛けています。なお、「あちゃんでいいの」の内部回路は書いていません。それと、液晶モジュール内のI2Cプルアップ抵抗を使っています。

▼ブレッドボード
ブレッドボード
 「あちゃんでいいの」を使ったおかげで、小さなブレッドボードに回路を全部詰め込むことが出来ました。液晶は秋月で買った8文字2行のもの(AE-AQM0802-W)で、その左はRTC-8564モジュール。手前の電池はRTCのバックアップ電源です。

 1秒間隔でRTCから割込みを掛けてCPUをスリープから復旧させ、必要な処理を行ったらすぐにスリープに入ることで消費電流を少なくしています。ちなみにスリープ時の消費電流は150μAでした。そのうち液晶が100μAくらい消費していたと思います。なお、CPUが動く時はそれなりの消費電流になります(3.3V、16MHzだと6mAくらい)が、時間は短いので電力量としてはかなり少なくなります。

 動作確認に使ったスケッチ 拡張子はtxtになっています。

 プログラムにはRTCの時刻合わせ機能などが入っていて行数が多いので、この記事中では全部は表示しませんが、主要部は以下のようになっています。
/*
リアルタイムクロックRTC8564BNと秋月のI2C液晶AQM0802A(8文字2行)のテスト
CPUをパワーダウンモードでスリープさせ、RTCからの割込みで処理を起動
RTCの時刻合わせ機能付き
RTC8564ライブラりは修正が必要
2016/2/2 ラジオペンチ http://radiopench.blog96.fc2.com/
*/

#include <avr/sleep.h> // 待機中はスリープさせるために使用
#include <Wire.h> //
#include <ST7032.h> // I2Cの液晶用ライブラリ オレ工房さん http://ore-kb.net/archives/195
#include <RTC8564.h> // なんでもつくっちゃう、かもさんのRTCライブラリ
#include <Wire.h>

ST7032 lcd;

char dtString[20] = "yyyy/mm/dd hh:mm:ss"; // テンプレート用文字列で初期化
byte RtcADR = 0XA2 >> 1;
int entB = 11; // EnterボタンのピンNo.
int selB = 9; // SelectボタンのピンNo.

void setup() {
pinMode(2, INPUT); // RTCの /INT信号を接続
digitalWrite(2, HIGH); // 相手はオープンドレインなのでプルアップ
pinMode(13, OUTPUT); // 動作表示LED
pinMode(entB, INPUT); // Enterボタン
pinMode(selB, INPUT); // Selectボタン
digitalWrite(entB, HIGH); // プルアップ
digitalWrite(selB, HIGH); // プルアップ

Serial.begin(9600);
lcd.begin(8, 2); // 8文字2行のI2C液晶を使用
lcd.setContrast(32); // 液晶コントラスト設定

Rtc.begin();
if (digitalRead(entB) == LOW) { // リセット時にEnterボタンが押されていたら
ClockSet(); // RTCの時刻を合わせる
}

// AdjustRtcTime(); // 時刻合わせが必要な場合に使う(固定値を強制書込み)
SetRtcTimer(); // 定周期タイマーの設定
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // スリープはパワーダウンモードで行う
}

void loop() {
waitExtIRQ(); // RTCからの1秒パルスを待つ
Rtc.available(); // 時刻を取得
convString(); // RTCの時刻(BCD)を文字列に変換してdtStringに格納

Serial.println(dtString); // シリアルに書き出し

dispClock(); // 液晶に表示
delay(20); // シリアル出力完了まで待つ
}


void waitExtIRQ() {
ADCSRA &= ~(1 << ADEN); // ADENビットをクリアしてADCを停止(120μA節約)
attachInterrupt(0, trigerd, FALLING); // Pin2のネガエッジで割込み
sleep_mode(); // 指定したモードでスリープ
detachInterrupt(0);
ADCSRA |= (1 << ADEN); // ADC動作再開
}

void trigerd() { // 割込み時の処理
}

以下省略
---------------------------

 ポイントは42行目の、 set_sleep_mode(SLEEP_MODE_PWR_DOWN); でパワーダウンモードを指定していることと、57行以降の割込み処理ルーチンのwaitExtIRQ()関数です。 それと、シリアルはハードウエアで実行されるためにプログラムとは非同期に処理されます。53行目のdelay()でこの処理の完了を待ってやらないと、激しく文字化けします。SLEEP_MODE_PWR_DOWNではほとんどのクロックを止めてしまうのでスリープ中はほぼ何も動きません。

 ちなみに、心配したI2Cですが、CPUがスリープしても全く影響を受けず動いていました。まあ電源を切っているわけではないので、I2Cのバスは全く変化しません。つまり、デバイス側から見たら何も起こっていないようにしか見えないので、当然といえば当然の結果でした。
関連記事

コメントの投稿

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

カレンダー
06 | 2017/07 | 08
- - - - - - 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コード