Hatena::ブログ(Diary)

hijouguchiの日記

2010-06-25

sleep

| 17:27 |

 いつもUSBで電源を確保していたのですが、ADCをいじっていたら「連流流れすぎ」とMacに怒られました...危ないですね。たぶん100mAは流れていないハズなんですけども...。

 余談はこれくらいにして、ADCの前に今回はsleepをやっておきます。


sleep概要

 sleepは文字通りavrをsleepさせて消費電力を抑えたり、あるいは電源スイッチを省略したり、さらにADC変換中にsleepにさせてADCの精度を上げる*1などなど出来ます。sleepからの復帰は割り込みを使い、sleepの種類によって使える割り込みが違います。


sleep mode一覧

modeINT割り込みTWIアドレス一致割り込みTimer2割り込みSPM/EEPROM Ready割り込みADC割り込みWDT割り込みOtherIO (PCINT?)
SLEEP_MODE_IDLEOOOOOOO
SLEEP_MODE_ADCLow LevelOOOOO-
SLEEP_MODE_PWR_DOWNLow LevelO---O-

 他にもSLEEP_MODE_PWR_SAVEとSLEEP_MODE_STANDBYがありますが、個人的に使わないので省略します。SLEEP_MODE_ADCはADCが搭載されたAVRでないとありません。割り込みの違い意外にクロック動作が変わってきてますが、プログラムを書く面から直接関係はしないと判断したのでこれも省略しています。

 INT割り込みの「Low Level」というのは状態変化・立ち上がり・立ち下がり割り込みでは復帰できないので注意です。


 sleepでは必要なレジスタはありますが、直接レジスタをいじることは無く、関数を呼び出して使います。使う関数

  • set_sleep_mode(mode)
  • sleep_mode()

の2種類だけです。set_sleep_modeで使用するスリープのモードを選び、sleep_modeで実際にスリープさせます。これらはavr/sleep.hに書かれているので、これをインクルードする必要はあります。復帰は割り込みを使うので、割り込みハンドラ無いにsleep_mode()を書くのは避けた方が良いです、割り込みフラグピットが落ちないままスリープして次回の割り込みがかからなくなる可能性があるので。


サンプルコード


 SLEEP_MODE_IDLE

 SLEEP_MODE_IDLEではTimerは停止しないので、動作自体はタイマ0の時のサンプルと変わりません。

タイマ0カウンタモード - hijouguchiの日記

/*
 * ATTiny2313
 * タイマを使ってPD6を反転させる
 * 8MHzで1024分周ならおよそ110ms周期で点滅
 */
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

/* 割り込みでスリープから復帰 */
ISR(TIMER0_OVF_vect)
{
  PORTD ^= (1<<PD6); // PD6反転
}

int main(void)
{
  /* PD6を出力L設定 */
  DDRD  =  (1<<PD6);
  PORTD = ~(1<<PD6);

  TIMSK  = (1<<TOIE0); // タイマ0のオーバーフロー割り込み許可
  TCCR0B = 0x05;       // 1024分周でカウントスタート

  set_sleep_mode(SLEEP_MODE_IDLE); // アイドルモードに設定

  sei();               // 全体の割り込み許可

  while(1) sleep_mode(); // 適宜スリープさせる
  return 0;
}

 SLEEP_MODE_PWR_DOWN

 こちらの場合、タイマ自体が停止するためスリープ中は止まります。

/*
 * ATTiny2313
 * タイマを使ってPD6を反転させる
 * 8MHzで1024分周ならおよそ110ms周期で点滅
 */
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

/* STATEが0でスリープ禁止、1でスリープ許可(とする) */
volatile unsigned char STATE;

ISR(TIMER0_OVF_vect)
{
  PORTD ^= (1<<PD6); // PD6反転
}

/* 割り込みでスリープから復帰 */
ISR(INT0_vect)
{
  STATE = 0; // スリープ禁止
}

int main(void)
{
  STATE = 0;

  /* PD6を出力L, その他をプルアップ有り入力に設定 */
  DDRD  =  (1<<PD6);
  PORTD = ~(1<<PD6);

  GIMSK = (1<<INT0)|(1<<INT1);  // INT0, 1の割り込み許可

  TIMSK  = (1<<TOIE0); // タイマ0のオーバーフロー割り込み許可
  TCCR0B = 0x05;       // 1024分周でカウントスタート

  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // アイドルモードに設定

  sei();               // 全体の割り込み許可

  while(1) {
    /* スリープ許可されてたら(PD6を消灯してから)スリープ */
    if(STATE == 1) {
      PORTD &= ~(1<<PD6);
      sleep_mode();
    }   

    /* PD5がLならスリープを許可 */
    if((~PIND & (1<<PD5)) == (1<<PD5)) STATE = 1;
  }
  return 0;
}

参考

403 Forbidden

ATTiny2313データシート http://www.atmel.com/dyn/resources/prod_documents/doc8246.pdf

エンデベッドシステムスペシャリスト合否

| 12:31 |

ESの結果が出たので見てきました。


平成22年度 春期 エンベデッドシステムスペシャリスト試験 成績照会

受験番号 ES***-*** の方は, 不合格 です

午前I得点68.00点
午前II得点84.00点
午後I得点57点
午後II得点---点

 午後IIに到達することすら出来ませんでした。たぶん1問出来てるか出来ないかのところでしょう。流石に勉強してただけでは大変で、仕事などで扱ってるようでないと到底合格できそうな気がしませんね...。「何msごとに割り込みがかかるか」「MPUの使用率はいくらか」知るか!

*1:クロックやピン変化自体がADCノイズになるため、sleepさせてこれを抑制させる

ススガススガ 2010/06/25 13:45 あ、この資格あったのわすれてた・・。興味ある・・