/* Alessandro Lambardi 14/02/2009 Released under Creative Commons 3.0 license: Attribution, Share-alike, non commercial. */ #define F_CPU 2457600UL // crystal frequency #include #include #include #include #include #define JUMP_0 0 // PORTA, jumper, display ceconds #define JUMP_1 1 // PORTA, jumper, set minutes #define JUMP_2 2 // PORTA, jumper, set hours #define JUMP_3 3 // PORTA, short for continuos LASER #define SERVO 5 // PORTA, output to servo #define LASER 6 // PORTA, output to LASER #define PWM_TOP F_CPU/60// TOP count for timer 0 (goes into OCR0A) //#define SERVO_MAX PWM_TOP*2.35/(1000/60) // max rotation is at 2.35ms pulse //#define SERVO_MIN PWM_TOP*0.70/(1000/60) // min rotation is at 0.70ms pulse #define SERVO_MAX PWM_TOP*1.65/(1000/60) // max rotation is at 2.35ms pulse #define SERVO_MIN PWM_TOP*0.75/(1000/60) // min rotation is at 0.70ms pulse // Variables that are set inside interrupt routines and watched outside must be volatile volatile uint8_t hour, min, sec, sxtyth; // hold the time volatile uint16_t servo_pos; // servo position (0 to PWM_TOP) ref to 00:00 volatile uint16_t servo_max, servo_min; // max/min value to servo for max/min position volatile uint8_t jumpers; // Interrupt service routines ISR(TIM1_OVF_vect) { // do time sxtyth++; if(sxtyth < 6) { // blink LASER for 2/10 of a sec PORTA |= _BV(LASER); } else{ if((PINA & _BV(JUMP_3)) != 0) { // if JUMP_3 not shorted turn LASER off PORTA &= ~_BV(LASER); } } if(sxtyth > 59){ sxtyth = 0; sec++; if(sec > 59){ sec = 0; min++; if(min > 59){ min = 0; hour++; if(hour > 12){ hour = 1; } } } } // set time : // set minutes if(((PINA & _BV(JUMP_1)) == 0) & ((sxtyth == 0) | (sxtyth == 30))){ min++; if(min > 59) { min = 0; } sec = 0; } // set hours if(((PINA & _BV(JUMP_2)) == 0) & ((sxtyth == 0) | (sxtyth == 30))){ hour++; if(hour > 12) { hour = 1; } min = 0; sec = 0; } if((PINA & _BV(JUMP_0)) == 0){ // evaluate servo position and display time servo_pos = servo_min + sec*((servo_max-servo_min)/59); // display seconds } else { servo_pos = servo_min + ((hour-1)*60+min)*((servo_max-servo_min)/(11*60+59)); } OCR1B = servo_min+servo_max-servo_pos; // clockwise // OCR1B = servo_pos; // counter clockwise } int main(void) { // enable pull-ups on pushbuttons PORTA = _BV(JUMP_0) | _BV(JUMP_1) | _BV(JUMP_2) | _BV(JUMP_3); // Port directions DDRA = _BV(SERVO) | _BV(LASER); // set outputs // Timer 1 (servo PWM): fast PWM mode 15, prescaler = 1, output on OC1B TCCR1A = _BV(WGM11) | _BV(WGM10) | _BV(COM1B1); TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); OCR1A = PWM_TOP; // PWM freq = 60Hz OCR1B = (SERVO_MAX + SERVO_MIN)/2;// initial position is halfway between MAX & MIN TIMSK1 = _BV(TOIE1); // enable timer overflow (for real time clock) // Set variables default hour = 1; min = 0; sec=0; sxtyth=0; servo_min=SERVO_MIN; servo_max=SERVO_MAX; sei(); // enable interrupts for(;;) { } }