SSブログ

リモコン信号機 (プロトタイプ tiny13) [Arduino]

先日のリモコン信号機 (プロトタイプ)を ATtiny13A に対応させてみました。
スケッチのサイズを1kバイト以内に収める工夫です。

attiny13a_s.jpg

1つめは、digitalWrite() などの関数です。
arduino-1.0.1/hardware/arduino/cores/arduino/wiring_digital.c を参考に新たに関数をつくりました。
・ATtiny13A にはポートBしかないので、ピン番号をそのままポートの番号として使う
・analogWriteを使用しないことにしてPWMのOFF処理をしない
・エラー処理はしない

2つめは、pulseIn() です。
arduino-1.0.1/hardware/arduino/cores/arduino/wiring_pulse.c を参考に新たに関数をつくりました。
・同様に、ポートB固定
・ピンがHIGHになるのを待つのを固定
・タイムアウトの時間を固定
・クロックサイクルの計算で結果を出しているけど、delayMicroseconds()を使う (精度は落ちる)
 (クロックサイクルの計算のときの割り算がサイズを大きくしているみたい)

ということで、新たな関数を作って、コンパイルすると、、

「コンパイル後のスケッチのサイズ:912バイト(最大容量1,024バイト)」

ということで、なんとか収まりました。
いちおう動作もしました。
 (でも、これらの関数が正しいのかどうかはわかりません。とりあえず動いたというだけです、、。)

ほんとは、もう1ピンあいているので、リモコン学習用にボタンをつけたり、Apple remoteなどにも対応させたりしたいので、結局 ATtiny45V を使うことになりそう、、。

// plarail remote control

#define LED_B   0          // LED (Blue)
#define LED_R   1          // LED (Red)
#define SERVO   2          // サーボモーター
#define IR_IN   4          // IR Receiver

void setup()  { 
  pinModeB( IR_IN , INPUT );
  pinModeB( LED_B, OUTPUT );
  pinModeB( LED_R, OUTPUT );
  pinModeB( SERVO, OUTPUT );
  setSignal(true);
}

void loop() {
  unsigned long irData;
  while( digitalReadB( IR_IN ) == HIGH );    // 赤外線を感知するまで待つ(信号としてはLOWになるまで待つ)
  irData = getIrNec();
  if( irData == 0x8C73BF40 ) setSignal(true);    // 青信号でGO
  if( irData == 0x8B74BF40 ) setSignal(false);   // 赤信号でSTOP
}

void setSignal(boolean s) {
  digitalWriteB( LED_B,  s );
  digitalWriteB( LED_R, !s );
  for( unsigned int i=0; i<50; i++ ) {
    digitalWriteB( SERVO, HIGH );
    delayMicroseconds( s ? 1000 : 2000 );
    digitalWriteB( SERVO, LOW );
    delayMicroseconds( s ? 19000 : 18000 );
  }
}

unsigned long getIrNec() {
  unsigned long irData = 0x00000000, irOff;
  while( digitalReadB( IR_IN ) == HIGH );    // 赤外線を感知するまで待つ(信号としてはLOWになるまで待つ)
  while( digitalReadB( IR_IN ) == LOW );     // リーダ部をやりすごす
  for( unsigned int dig = 0; dig < 32; dig++ ) {  // データを32桁読み込む  
    irOff = pulseInCustum( IR_IN );               // 赤外線消灯時間(信号としてはHIGHの時間)
    if( irOff == 0 ) return 0UL;               // 信号途絶なら終了
    if( irOff > 1000 ) irData |= 1UL << dig;     // Data=1 とき
  }
    // ストップビットを確認しないかわりに、データビットの確認
  if( (byte)((irData>>16)^(irData>>24)) != 0xff ) return 0UL;
  return irData;
}

unsigned long pulseInCustum(uint8_t pin)
{
  // pulseInのBポート固定、High固定、Timeout固定、精度100usecにした関数
  uint8_t bit = 1 << pin;
  unsigned long width = 0;
  unsigned long numloops = 0;
  unsigned long maxloops = 10000 / 100;  // タイムアウトを10000usec, 1ループ100usecのdelay
	
  while (PINB & bit) {      // wait for any previous pulse to end
    delayMicroseconds(100);
    if (numloops++ == maxloops)  return 0;
  }
  while (!(PINB & bit)) {   // wait for the pulse to start
    delayMicroseconds(100);
    if (numloops++ == maxloops)  return 0;
  }
  while (PINB & bit) {      // wait for the pulse to stop
    delayMicroseconds(100);
    if (numloops++ == maxloops)  return 0;
    width += 100;
  }
  return width; 
}

// ポートB のみの ATtiny13/45/85用 デジタル専用入出力
// PWMは使用しない。エラー未対応。など制限あるけどややコードが小さくなる

void pinModeB(uint8_t pin, uint8_t mode) {
  uint8_t bit = 1 << pin;
  uint8_t oldSREG = SREG;
  cli();
  if (mode == INPUT) {             DDRB &= ~bit;  PORTB &= ~bit; }
  // else if (mode == INPUT_PULLUP) { DDRB &= ~bit;  PORTB |=  bit; }
  else {                           DDRB |=  bit; }
  SREG = oldSREG;
}

void digitalWriteB(uint8_t pin, uint8_t val) {
  uint8_t oldSREG = SREG;
  cli();
  if (val == LOW)  PORTB &= ~(1 << pin);
  else             PORTB |=  (1 << pin);
  SREG = oldSREG;
}

int digitalReadB(uint8_t pin) {
  return (PINB & (1 << pin)) ? HIGH : LOW;
}

nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。