/* Name: main.c * Author: Toshi Nagata * Copyright: 2009-2018 (c) Toshi Nagata * License: Modified BSD License * * Clock: Internal 1.2MHz * Pin 6 (PB1): IR LED * Pin 5/7/2/3 (PB0/2/3/4) Button forward/left/right/backward */ #include #include #include #include #define F_CPU 1200000.0 #define ON_T (unsigned short)(F_CPU/4000000.0*340) #define OFF_T_0 (unsigned short)(F_CPU/4000000.0*680) #define OFF_T_1 (unsigned short)(F_CPU/4000000.0*340*5) #define GAP_T (unsigned short)(F_CPU/4000000.0*45000) inline void pwm_on(void) { TCCR0A |= 0b00110000; // high (connect OC0B to PWM) } inline void pwm_off(void) { TCCR0A &= 0b11001111; // low (disconnect OC0B from PWM) PORTB &= 0b11111101; // output 0 to OC0B(=PB1) } void output_one(void) { pwm_on(); _delay_loop_2(ON_T); pwm_off(); _delay_loop_2(OFF_T_1); } void output_zero(void) { pwm_on(); _delay_loop_2(ON_T); pwm_off(); _delay_loop_2(OFF_T_0); } void output_data(unsigned short d) { unsigned char i; d = (d << 5) | 0x10; for (i = 16; i != 0; i--) { if ((d & 1) != 0) output_one(); else output_zero(); d >>= 1; } } unsigned short data; int main(void) { cli(); // Disable interrupt DDRB = 0b00000010; // PB1 for output PORTB = 0b00011101; // PB0/2/3/4 enable pull-up // timer0: Highspeed PWM for 38kHz duty 1/3 Output (to OC0B) // internal 1.2MHz, prescale 1/1: 1 timer clock = 0.83 us // 38kHz 1 cycle = 26.3 us = 32 clocks, duty 1/3: 11:21 TCCR0A = 0b00110011; // Set OC0B at Compare Match (=OCR0B) and clear at TOP TCCR0B = 0b00001001; // Prescale 1/1, Fast PWM with TOP = OCR0A TCNT0 = 0; OCR0A = 32; // PWM interval 560uS OCR0B = 21; // Duty 1/3 (clear=21 clocks, set=32-21=11 clocks) GIMSK = 0b00100000; /* PCINT enabled */ PCMSK = 0b00011101; // PCINT0/2/3/4 (pins 5/7/2/3) enabled set_sleep_mode(SLEEP_MODE_IDLE); pwm_off(); sei(); // Enable interrupt while (1) { unsigned char b = PINB; /* Copy bit 0 to bit 1 */ if ((b & 0b00000001) == 0) b &= 0b11111101; else b |= 0b00000010; b = (~b >> 1) & 0x0f; if (b != 0) { data = b | 0x40; output_data(data); _delay_loop_2(GAP_T); output_data(0x03ff ^ data); _delay_loop_2(GAP_T); } else { sleep_enable(); sleep_cpu(); // Sleep until interrupt sleep_disable(); // Wake up } } return 0; }