・棒を一生懸命振ると、赤外線信号が発信されるリモコン送信機と受信機のセットだ。送信機のハードウェアを改良するとともに、送信機と受信機のファームウェアを改良した。
・今度のモデルでは、14種類のコマンドを区別してプログラムできる。プログラムを作りさえすれば一つの回路で14chのコントローラが作れるともいえる。
・本機に内蔵された圧電振動ジャイロモジュールが振動を検出したときに、周波数38kHzの赤外線信号を出力する。プログラムによって、4ビットのコマンドを送信することができる。理論的には16種類のコマンドが表現できるが、プロトコルが単純なので、14種類しか識別できない。(コマンドプロトコルについては添付ファイルを参照)
・回路図やファームウェアのソースなどは、添付ファイルを参照のこと。
・今回の回路では、スライドスイッチにより、2種類のコマンドを切り替えて送信する。
・ケースには、有名なチョコレート菓子のパッケージを再利用した。
・Eagle形式の回路図やファームウェアのバイナリファイル(HEXファイル)などは、添付ファイルを参照のこと。
圧電振動ジャイロモジュール (村田製作所ENC-03R使用、秋月電子通商)
AVRマイコン ATMEGA168P
赤外線LED
LED(発信状態のモニタ用)
カーボン抵抗器 150Ω, 1kΩ
積層セラミックコンデンサ 0.1uF
ユニバーサル基板(ケースのサイズに合わせて切り取ったもの)
28ピンICソケット
スライドスイッチ×2個
電池ボックス(単4型1本用)×2個
※AVRマイコンの出荷時クロック周波数(1MHz)で動作するように設定した。
※パルスは、38kHzで変調されている。
// Mega168 Ir-LED Remote Contorller Unit ( Transmitter )// AVR Device : ATmega168 @ CK 1MHz ( or 8MHz )// OC1B(PB2) : IR-LED// PB0, PB1 : LED 1:ON, 0:OFF// PB6 : Command Select Switch // ADC0, ADC1 (PIN23, 24)#include <avr/io.h>#include <avr/interrupt.h>#define led0_on() ( PORTB |= (1<<PB0) )#define led0_off() ( PORTB &= ~(1<<PB0) )#define is_sw() (PINB & (1<<PB6))#define irled_on() ( PORTB |= (1<<PB2) )#define irled_off() ( PORTB &= ~(1<<PB2) )#define ADC_VAL_MIN 0x60#define ADC_VAL_MAX 0xb0volatile unsigned int TIMER1F = 0;ISR(TIMER1_COMPA_vect){ TIMER1F++;}//#define FREQ38KHZ 96 // (CK 8Mhz) value of OCR1A at 38kHz Frequency #define FREQ38KHZ 12 // (CK 1Mhz) value of OCR1A at 38kHz Frequency #define FREQZERO 0 // value of OCR1A at No Frequency void init_timer1_ctc(void)// Timer/Counter1 を CTC (Clear Timer on Compare mode)モードで初期化{ // Freq = IOclock (1MHz or 8MHz) / 2N(1 + OCR1A) , N=1(no Prescaling) TCCR1A = (0<<WGM11) | (0<<WGM10) | (0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (1<<COM1B0); TCCR1B = (0<<WGM13) | (1<<WGM12) | (0<<CS12) | (0<<CS11) | (1<<CS10); OCR1A = FREQ38KHZ; OCR1B = 0x0000; // Freq. 38kHz TIMSK1 |= (1<<OCIE1A);}void connect_OC1(void){ TCCR1A = (0<<WGM11) | (0<<WGM10) | (0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (1<<COM1B0);}void disconnect_OC1(void){ TCCR1A = (0<<WGM11) | (0<<WGM10) | (0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0);}#define PULSEWIDTH 100 // Signal Pulse Interval (Number of TIMER1 Interrupt) #define BLANKWIDTH 1500 // Signal blank Interval (Number of TIMER1 Interrupt) void out_bit_1(void){ connect_OC1(); TIMER1F = 0; while( TIMER1F < PULSEWIDTH);}void out_bit_0(void){ disconnect_OC1(); TIMER1F = 0; while( TIMER1F < PULSEWIDTH);}void out_blank(void){ disconnect_OC1(); TIMER1F = 0; while( TIMER1F < BLANKWIDTH );}void output_command_pattern(uint8_t bit_pattern){ out_bit_1();//START bit if ( bit_pattern & 0x01) { out_bit_1(); } else { out_bit_0(); } if ( bit_pattern & 0x02 ) { out_bit_1(); } else { out_bit_0(); } if ( bit_pattern & 0x04 ) { out_bit_1(); } else { out_bit_0(); } if ( bit_pattern & 0x08 ) { out_bit_1(); } else { out_bit_0(); } out_blank();}void init_adc(void){ // AD Conv. Enable & Clock ferquency and the input clock to the ADC) ADCSRA = ( (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0) ); }uint8_t get_ad(char adcport)// arg: adcport : 0 - { cli(); // Disable Interrupt ADMUX = (1<<ADLAR) | adcport; // AD-Conv. 8-bit precision, Use ADC-PORT0 ADCSRA |= (1<<ADIF); // Set ADC Interrupt flag ADCSRA |= (1<<ADSC); // Start AD Conv. while ( ( ADCSRA & (1<<ADIF) ) == 0); //Wait to complete adc sei(); //Enable Interrupt return (uint8_t)ADCH; // 8-bit precision} #define COMMAND06 0x06#define COMMAND09 0x09int main(void){ uint8_t s0, s1; uint8_t command = COMMAND06; init_timer1_ctc(); // CTC mode init_adc(); // ADC port initialize // PORTB2, 1, 0 を出力モード, PORTB6 Input mode Pullup Resister ON PORTB |= (1<<PB6); DDRB = (1<<PB2) | (1<<PB1)| (1<<PB0); // PORTC0,1,2,3 Input mode PORTC = 0xff; DDRC = ~( (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3) ); // PORTD2, 3 Input mode PORTD = 0xff; DDRD = ( (0<<PD2) | (0<<PD3) ); disconnect_OC1(); OCR1A = 0; led0_off(); // At First, No OUTPUT sei(); // interrupt enable while(1) { // Setup Command code if (is_sw()) { command = COMMAND06; } else { command = COMMAND09; } // Detect Vibration s0 = get_ad(0x00); // ADC0 s1 = get_ad(0x01); // ADC1 // Control Signal Output if ( (ADC_VAL_MIN < s0 && s0 < ADC_VAL_MAX) || (ADC_VAL_MIN < s1 && s1 < ADC_VAL_MAX)) { disconnect_OC1(); OCR1A = 0; led0_off(); } else { led0_on(); OCR1A = FREQ38KHZ; output_command_pattern(command); output_command_pattern(command); output_command_pattern(command); output_command_pattern(command); output_command_pattern(command); } } return 0;}# AVR-GCC MakefilePROJECT=transmitter-mega168SOURCES=transmitter-mega168.cCC=avr-gccOBJCOPY=avr-objcopyMMCU=atmega168TARGETDEV=m168PCFLAGS=-mmcu=$(MMCU) -Wall$(PROJECT).hex: $(PROJECT).out$(OBJCOPY) -j .text -O ihex $(PROJECT).out $(PROJECT).hex
$(PROJECT).out: $(SOURCES)$(CC) $(CFLAGS) -I./ -o $(PROJECT).out $(SOURCES)
program: $(PROJECT).hexsudo avrdude -p $(TARGETDEV) -P usb -c avrispmkII -e -U flash:w:$(PROJECT).hex
clean:rm -f $(PROJECT).out
rm -f $(PROJECT).hex
・発信された赤外線信号を受信して動くロボットも作ってみた。このロボットは、以前作成した「イタスマシ」に、赤外線リモコン受信モジュールを接続し、ファームウェアを変更したもの。
・このロボットは、2台の送信機から送られてくる別々のコマンドに反応する。といっても動作は単純で、1台の送信機からの信号で右のモータが回転し、別の1台の送信機からの信号で左のモータが回転するだけだ。
AVRマイコン ATtiny2313V
赤外線リモコン受信モジュール PL-IRM2161-C438 (3V動作対応)
FET 2SK2231 (2個)
ショットキーバリアダイオード 1S10
整流用ダイオード 1N4007 (2個)
電解コンデンサ 470uF (2個)
カーボン抵抗 150Ω(2本), 1kΩ, 10kΩ
20ピンICソケット
スライドスイッチ
ユニバーサル基板
バッテリースナップ
電池ボックス(単3型2本用)
※赤外線受信モジュールPL-IRM2161-C438の出力は、Active Lowなので、送信側と電圧レベルが逆になる。
// INT0/PD2 : Ir-remote controller unit ( Reciever )// PB4, PB3 : Motor driver// PB0 : LED#include <avr/io.h>#include <avr/interrupt.h>#define led_off() ( PORTB |= (1<<PB0) )
#define led_on() ( PORTB &= ~(1<<PB0) )
#define led() ( PINB |= (1<<PB0) )#define motor0_on() ( PORTB |= (1<<PB3) )#define motor1_on() ( PORTB |= (1<<PB4) )#define motor0_off() ( PORTB &= ~(1<<PB3) )#define motor1_off() ( PORTB &= ~(1<<PB4) )#define is_ir() ( PIND & (1<<PD2) )volatile unsigned int TIMER1F = 0;ISR(TIMER1_COMPA_vect){ TIMER1F++;}//#define FREQ38KHZ 96 // (CK 8Mhz) value of OCR1A at 38kHz Frequency #define FREQ38KHZ 12 // (CK 1Mhz) value of OCR1A at 38kHz Frequency #define FREQZERO 0 // value of OCR1A at No Frequency void init_timer1_ctc(void)// Timer/Counter1 を CTC (Clear Timer on Compare mode)モードで初期化{ // Freq = IOclock (1MHz or 8MHz) / 2N(1 + OCR1A) , N=1(no Prescaling) TCCR1A = (0<<WGM11) | (0<<WGM10) | (0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0); TCCR1B = (0<<WGM13) | (1<<WGM12) | (0<<CS12) | (0<<CS11) | (1<<CS10); OCR1A = FREQ38KHZ; OCR1B = 0x0000; // Freq. 38kHz TIMSK |= (1<<OCIE1A);}#define PULSEWIDTH 100 // Signal Pulse Interval (Number of TIMER1 Interrupt) #define BLANKWIDTH 1000 // Signal blank Interval (Number of TIMER1 Interrupt) #define COMMANDWIDTH 2000 // Signal COMMAND Sequence Period (Number of TIMER1 Interrupt) #define PATTERN_NG 0xffuint8_t get_data(void){ uint8_t d = 0; uint8_t i; if ( is_ir() ) { led_off(); // Search blank period TIMER1F = 0; while ( is_ir() ) { if (TIMER1F >= COMMANDWIDTH ) return PATTERN_NG; } if ( TIMER1F >= BLANKWIDTH ) { led_on(); // Wait for Start Bit while ( is_ir() ); for ( i = 0; i < 4; i++) { // Step to Next Pulse TIMER1F = 0; while ( TIMER1F < PULSEWIDTH ) { // Data BIt 1 if ( is_ir() == 0 ) { d |= (1<<i); led_on(); } else { d |= (0<<i); led_off(); } } } } return d;}uint8_t generate_bit_data(uint8_t bit_pattern){ uint8_t data = 0; int i; for (i = 3; i >= 0; i-- ) { data |= ( ( bit_pattern & 0x01) << i); bit_pattern >>= 1; } return data;}#define COMMAND06 0x06int main(void){ uint8_t d, target; // Initialize I/O Port PORTD &= ~(1<<PD2); DDRD &= ~(1<<PD2) ; // PD2 Input Mode DDRB = (1<<PB0) | (1<<PB3) | (1<<PB4); init_timer1_ctc(); sei(); while (1) { // Test Recieve Data Pattern d = get_data(); target = generate_bit_data(COMMAND06); if (d == target) { motor0_on(); motor1_off(); } else if (d == ( (~target) & 0x0f) ) { // reverse bit pattern motor0_off(); motor1_on(); } else { motor0_off(); motor1_off(); } } return 0;}# AVR-GCC MakefilePROJECT=ir-reciever-tiny2313SOURCES=ir-reciever-tiny2313.cCC=avr-gccOBJCOPY=avr-objcopyMMCU=attiny2313TARGETDEV=t2313CFLAGS=-mmcu=$(MMCU) -Wall$(PROJECT).hex: $(PROJECT).out$(OBJCOPY) -j .text -O ihex $(PROJECT).out $(PROJECT).hex
$(PROJECT).out: $(SOURCES)$(CC) $(CFLAGS) -I./ -o $(PROJECT).out $(SOURCES)
program: $(PROJECT).hexsudo avrdude -p $(TARGETDEV) -P usb -c avrispmkII -e -U flash:w:$(PROJECT).hex
clean:rm -f $(PROJECT).out
rm -f $(PROJECT).hex