リモコン信号機 (プロトタイプ tiny13) [Arduino]
先日のリモコン信号機 (プロトタイプ)を ATtiny13A に対応させてみました。
スケッチのサイズを1kバイト以内に収める工夫です。
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 を使うことになりそう、、。
スケッチのサイズを1kバイト以内に収める工夫です。
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;
}
2012-09-26 07:44
nice!(0)
コメント(0)
トラックバック(0)
コメント 0