ATtiny1614で、DS3231 RTCモジュールのアラーム信号を受け取って割り込み処理を行う。
毎記事、自身の覚書としてだけではなく、できる限り皆さんのお役に立てばと考えて拙い文章を連ねている。今回は、それに加えてもう一つ。感染症が流行している際は、不特定多数の人とできるだけ接触しないこと、手洗い・うがいといった基本的な衛生行動を怠らないこと、そして、正しい情報を正しく理解すること。本稿記載時点でなお、COVID-19は猛威を振るっている。
さて本題。Arduino(Pro Mini互換機)でDS3231 RTCモジュールのアラーム信号を受け取って割り込み処理する手順を以前の記事に記した。また、megaTinyCoreを使用すると、ATtiny1614がArduino同様に開発できることも前回の記事で示した。実際に、Lチカだけではなく、DS3231でも使用可能なDS3232のライブラリーと液晶表示器コントローラーST7032のライブラリーを使った下記スケッチがArduino(Pro Mini互換機)でもATtiny1614でも動作することを確認している。
#include <DS3232RTC.h>
#include <ST7032.h>
DS3232RTC clock;
ST7032 lcd;
void setup() {
clock.begin();
lcd.begin(8, 2);
lcd.setContrast(20);
}
void loop() {
time_t now = clock.get();
char line[8];
sprintf(line, "%02d-%02d-%02d", year(now)%100, month(now), day(now));
lcd.setCursor(0, 0);
lcd.print(line);
sprintf(line, "%02d:%02d:%02d", hour(now), minute(now), second(now));
lcd.setCursor(0, 1);
lcd.print(line);
delay(10);
}
では割り込み処理も同様に、と考えたくなるのが世の道理。ところが、attachInterrupt()
関数が予期したとおりに動作しないようである。Arduino IDEでのコンパイル時に下記の警告が出ていたのも、いかにも不吉であった(関係はなかった)。
警告:ライブラリDS3232RTC-masterはアーキテクチャavrに対応したものであり、アーキテクチャmegaavrで動作するこのボードとは互換性がないかもしれません。
Web上をさまようこと数時間、何のことはない、megaTinyCoreの作者さんが丁寧な解説に加えてサンプルコードまで示してくださっていた。Well, I understand. それを基に修正したのが以下のコードである。割り込みは、「完全に非同期的に」割り込み信号を受け取れるPA6(=4番ピン)を使用した。
#include <DS3232RTC.h>
#include <avr/power.h>
#include <avr/sleep.h>
const byte ALARM_IN_USE = ALARM_1; // every second
const uint8_t MAX_ALARM_COUNT = 5; // every 5 seconds
const uint8_t INT_PIN = 2; // PA6
const uint8_t LED_PIN = 5; // PB2
volatile boolean caught_alarm = false;
uint8_t alerm_count = 0;
DS3232RTC clock;
void setup(void) {
power_all_enable();
pinMode(INT_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
/* bits 0-2: 011 = FALLING, bit 3: 1 = PULLUP */
PORTA.PIN6CTRL = 0b00001011;
clock.alarmInterrupt(ALARM_1, false);
clock.alarmInterrupt(ALARM_2, false);
clock.squareWave(SQWAVE_NONE);
clock.oscStopped(true);
clock.setAlarm(ALM1_EVERY_SECOND, 0, 0, 0, 1);
clock.setAlarm(ALM2_EVERY_MINUTE, 0, 0, 0, 1);
clock.alarm(ALARM_IN_USE);
clock.alarmInterrupt(ALARM_IN_USE, true);
}
void loop(void) {
if (caught_alarm) {
caught_alarm = false;
alerm_count++;
if (alerm_count >= MAX_ALARM_COUNT) {
alerm_count = 0;
doWork();
}
clock.alarm(ALARM_IN_USE);
}
enterSleep();
}
ISR(PORTA_PORT_vect) {
register8_t flags = PORTA.INTFLAGS;
PORTA.INTFLAGS = flags; // clear flags; set 1 if flag = 1
caught_alarm = true;
}
void enterSleep(void) {
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode();
/* wait for alarm */
sleep_disable();
}
void doWork(void) {
power_all_enable();
digitalWrite(LED_PIN, HIGH);
delay(100);
digitalWrite(LED_PIN, LOW);
delay(100);
digitalWrite(LED_PIN, HIGH);
delay(100);
digitalWrite(LED_PIN, LOW);
}
UPDI programmerである“jtag2updi”の使い方と配線は前回の記事を参照されたい。Arduino Pro Mini互換機経由で上記スケッチをATtiny1614に書き込んだ後、以下のとおり配線する。注意すべきは、スケッチでのピン番号と実際のピン番号とのずれである。
- ATtiny1614の4番ピンとDS3231 RTCモジュールのSQWを繋ぐ
- ATtiny1614の7番ピンとGNDをLチカ用LEDで繋ぐ
- ATtiny1614の8番ピンとDS3231 RTCモジュールのSDAを繋ぐ
- ATtiny1614の9番ピンとDS3231 RTCモジュールのSCLを繋ぐ
- ATtiny1614の14番ピンとGNDを繋ぐ
- ATtiny1614の1番ピンとVccを繋ぐ
相変わらず手振れのひどい動画で申し訳ない。スリープ時には約0.5 mA、動作時には約2.5 mA(RTCモジュール込み、LED無し)で動作していた。
コメント