/***************************************************** This program was produced by the CodeWizardAVR V1.25.7a Standard Automatic Program Generator © Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l. http://www.hpinfotech.com Project : Version : Date : 12/14/2009 Author : Theodore Johnson Company : Comments: Chip type : ATmega168 Program type : Application Clock frequency : 8.000000 MHz Memory model : Small External SRAM size : 0 Data Stack size : 256 *****************************************************/ #include #include // Standard Input/Output functions #include // for abs() #include // button and indicators for testing #define BTN PINC.5 #define LED_R PORTB.0 #define LED_B PORTB.1 #define LED_G PORTB.2 #define PANEL_ENABLE PORTB.7 // The PWM outputs #define PANEL_R PORTD.6 #define PANEL_G PORTD.5 #define PANEL_B PORTD.3 #define MOUSE_CLK PIND.2 #define MOUSE_DATA PIND.4 #define MOUSE_CLK_OUT PORTD.2 #define MOUSE_DATA_OUT PORTD.4 // mouse input processing #define NSLOTS 10 unsigned char wpos=0; unsigned char rpos=0; unsigned char inval[NSLOTS]; unsigned int ints[NSLOTS]; unsigned char fail_code = 0; unsigned char fail_count=0; ///////////////////////////////////////////////// /// Input Functions unsigned char button_pressed(unsigned char b, unsigned char *s){ unsigned char retval; if(b == 1 && *s == 0) retval = 1; else retval = 0; *s = ((*s) << 1) + b; return(retval); } //////////////////////////////////////////////// // PS2 mouse functions // External Interrupt 0 service routine interrupt [EXT_INT0] void ext_int0_isr(void){ unsigned char i, fail=0; unsigned char val=0, bpos, nbits=0, parity; unsigned char tsl, tsh; unsigned int ts; // start bit if(MOUSE_DATA != 0){ fail_code=3; fail_count++; EIFR=1; return; } for(i=0;i<15;i++){ if(MOUSE_CLK == 1) break; delay_us(10); } if(i>=15){ fail_code = 5; fail_count++; EIFR=1; return; } // Data for(bpos=1; bpos!=0 && fail==0; bpos = bpos << 1){ for(i=0;i<12;i++){ if(MOUSE_CLK == 0) break; delay_us(10); } if(i>=12){ fail_code = bpos; fail_count++; EIFR=1; break; } if(MOUSE_DATA==1){ val = val | bpos; nbits++; } for(i=0;i<12;i++){ if(MOUSE_CLK == 1) break; delay_us(10); } if(i>=12){ fail_code = bpos; fail_count++; EIFR=1; break; } } if(fail) return; // Parity bit for(i=0;i<12;i++){ if(MOUSE_CLK == 0) break; delay_us(10); } if(i>=12){ fail_code = 7; fail_count++; EIFR=1; return; } if(MOUSE_DATA==1) parity = 1; for(i=0;i<12;i++){ if(MOUSE_CLK == 1) break; delay_us(10); } if(i>=12){ fail_code = 11; fail_count++; EIFR=1; return; } // stop bit for(i=0;i<12;i++){ if(MOUSE_CLK == 0) break; delay_us(10); } if(i>=12){ fail_code = 15; fail_count++; EIFR=1; return; } if(MOUSE_DATA==0){ fail_code = 19; fail_count++; } for(i=0;i<12;i++){ if(MOUSE_CLK == 1) break; delay_us(10); } if(i>=12){ fail_code = 23; fail_count++; EIFR=1; return; } nbits=1; for(bpos=1; bpos!=0 && fail==0; bpos = bpos << 1){ if(bpos & val) nbits++; } if((nbits & 0x01) != parity){ fail_code = 27; fail_count++; } tsl = TCNT1L; tsh = TCNT1H; ts=tsh; ts = ts<<8; ts|=tsl; inval[wpos] = val; ints[wpos] = ts; wpos++; if(wpos>=NSLOTS){ wpos=0; } // disable the interrupt-trigger bit, // which will have been set in the course of the interrupt service handler. EIFR=1; } unsigned char get_mouse_update(unsigned char *v, unsigned int *ts){ #asm("cli") if(rpos==wpos){ #asm("sei"); return 0; } *v=inval[rpos]; *ts=ints[rpos]; rpos++; if(rpos>=NSLOTS) rpos=0; #asm("sei"); return 1; } unsigned char send_mouse_command(unsigned char c){ unsigned char i, bpos, ret=0, nbits=0; unsigned char prev_ddrd; #asm("cli") // The mouse is connected to port D. // This code will manipulate DDRD, so save // it for later restoration. prev_ddrd = DDRD; MOUSE_DATA_OUT=1; MOUSE_CLK_OUT=1; DDRD = 0x16; MOUSE_CLK_OUT = 0; delay_us(150); MOUSE_DATA_OUT=0; delay_us(5); MOUSE_CLK_OUT=1; DDRD = 0x12; for(i=0;i<20;i++){ if(MOUSE_CLK==0) break; delay_us(10); } if(i>=20){ ret=7; goto end; } for(bpos=1;bpos!=0;bpos=bpos<<1){ if(bpos & c){ MOUSE_DATA_OUT = 1; nbits++; }else{ MOUSE_DATA_OUT = 0; } for(i=0;i<12;i++){ if(MOUSE_CLK==1) break; delay_us(10); } if(i>=12){ ret=bpos; goto end; } for(i=0;i<12;i++){ if(MOUSE_CLK==0) break; delay_us(10); } if(i>=12){ ret=bpos; goto end; } } // Parity bit if(nbits&1){ MOUSE_DATA_OUT=0; }else{ MOUSE_DATA_OUT=1; } for(i=0;i<12;i++){ if(MOUSE_CLK==1) break; delay_us(10); } if(i>=12){ ret=11; goto end; } for(i=0;i<12;i++){ if(MOUSE_CLK==0) break; delay_us(10); } if(i>=12){ ret=15; goto end; } // STOP bit MOUSE_DATA_OUT = 1; for(i=0;i<12;i++){ if(MOUSE_CLK==1) break; delay_us(10); } if(i>=12){ ret=19; goto end; } for(i=0;i<12;i++){ if(MOUSE_CLK==0) break; delay_us(10); } if(i>=12){ ret=31; goto end; } DDRD= 0x02; for(i=0;i<20;i++){ if(MOUSE_DATA==1) break; delay_us(10); } if(i>=20){ ret=63; goto end; } for(i=0;i<12;i++){ if(MOUSE_CLK==1) break; delay_us(10); } if(i>=12){ ret=127; goto end; } // C doesn't have a finally clause, hack it with goto statements. end: DDRD = prev_ddrd; // restore DDRD EIFR=1; // the output processing shouldn't trigger an interrupt. #asm("sei"); return ret; } unsigned char init_mouse(){ unsigned char err, done, pos, v, iter, ret; unsigned int lts; // Wait for mouse initialization pos=0; err = 0; done=0; iter = 0; while(! done){ if(get_mouse_update(&v, <s)){ switch(pos){ case 0: if(v != 0xAA) err=1; pos++; break; case 1: if(v != 0x00) err=2; pos++; done=1; break; } } iter++; if(iter>50){ err=iter; done=1; } delay_ms(100); } err=0; iter=0; pos=0; ret = send_mouse_command(0xf4); while(iter<200){ if(get_mouse_update(&v, <s)){ if(v!=0xfa) err=3; break; } delay_ms(10); iter++; } if(iter>=200) err = iter; return err; } // Handle counter wraparound unsigned int time_diff(unsigned int t1, unsigned int t2){ if(t1>t2) return t1-t2; return t1 + (65535-t2) +1; } unsigned char m_pos = 0; unsigned int last_sample = 0; unsigned char m_stat, m_dx, m_dy; // mouse status updates come in triplets. // gather the triplets, and ensure that // they come close together, else we might // get unsynchronized unsigned char sample_mouse(){ unsigned int lts; unsigned char v; if(get_mouse_update(&v, <s)){ if(time_diff(lts, last_sample) > 60){ m_pos = 0; } last_sample = lts; switch(m_pos){ case 0: m_stat = v; break; case 1: m_dx = v; break; case 2: m_dy = v; break; } m_pos++; if(m_pos>=3) m_pos=0; if(m_pos==0) return 1; } return 0; } #define RMB_PRESSED (m_stat & 0x02) #define LMB_PRESSED (m_stat & 0x01) unsigned char l_mbtn=0, r_mbtn=0; unsigned int xpos, ypos; int xdelta, ydelta; #define MAXPOS 255 // Process mouse input. Extract the mouse // movement into xdelta, ydelta. the return // vlaue includes the button status. unsigned char update_mouse_pos(){ unsigned int ret = 0; if( sample_mouse() ){ xdelta = m_dx; if(xdelta!=0) ret=4; if(m_stat & 0x10){ xdelta = (255-xdelta)+1; if(xdelta>xpos) xpos=0; else xpos -= xdelta; xdelta = -xdelta; }else{ if(MAXPOS-xpos <= xdelta) xpos=MAXPOS; else xpos += xdelta; } ydelta = m_dy; if(ydelta!=0) ret=4; if(m_stat & 0x20){ ydelta = (255-ydelta)+1; if(ydelta>ypos) ypos=0; else ypos -= ydelta; ydelta = -ydelta; }else{ if(MAXPOS-ypos <= ydelta) ypos=MAXPOS; else ypos += ydelta; } if(l_mbtn==0 && LMB_PRESSED) ret |= 1; if(r_mbtn==0 && RMB_PRESSED) ret |= 2; l_mbtn=LMB_PRESSED; r_mbtn=RMB_PRESSED; return ret; } return 0; } #define NONE 0 #define LUM 1 #define RB 2 #define BG 3 #define RG 4 // Interpret mouse gestures. // left-right : blue-red // up-down : hi-low // diagional, positive slope : blue-green // diagonal, negative slope : red-green unsigned char classify_movement(int *magnitude){ if(xdelta==0 && ydelta==0) return NONE; if(abs(xdelta) > (abs(ydelta) << 1)){ // red-blue, sign points to R *magnitude = xdelta; return RB; } if(abs(ydelta) > (abs(xdelta) << 1)){ // luminosity *magnitude = ydelta; return LUM; } if( (xdelta>0 && ydelta>0) || (xdelta<0 && ydelta<0) ){ // BG, sign points to G if(abs(xdelta) > abs(ydelta)) *magnitude = xdelta; else *magnitude = ydelta; return BG; } // RG, sign points to G if(abs(xdelta) > abs(ydelta)) *magnitude = -xdelta; else *magnitude = ydelta; return RG; } #define RED 0 #define GREEN 1 #define BLUE 2 #define MAXLUM 63 unsigned int lum = 32; unsigned int weight[3]; void main(void){ unsigned char btn, pos, ret, action, state; int magnitude; unsigned char wmax; unsigned long int wg, wb, wr; unsigned int vb,vr,vg; // Crystal Oscillator division factor: 1 #pragma optsize- CLKPR=0x80; CLKPR=0x00; #ifdef _OPTIMIZE_SIZE_ #pragma optsize+ #endif // Input/Output Ports initialization // Port B initialization // Func7=Out Func6=In Func5=In Func4=In Func3=In Func2=Out Func1=Out Func0=Out // State7=0 State6=T State5=T State4=T State3=T State2=0 State1=0 State0=0 PORTB=0x00; DDRB=0x87; // Port C initialization // Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In // State6=T State5=T State4=T State3=T State2=T State1=T State0=T PORTC=0x00; DDRC=0x00; // Port D initialization // Func7=In Func6=Out Func5=Out Func4=In Func3=Out Func2=In Func1=Out Func0=In // State7=T State6=0 State5=0 State4=T State3=0 State2=T State1=0 State0=T PORTD=0x00; DDRD=0x6A; // Timer/Counter 0 initialization // Clock source: System Clock // Clock value: 31.250 kHz // Mode: Phase correct PWM top=FFh // OC0A output: Non-Inverted PWM // OC0B output: Non-Inverted PWM TCCR0A=0xA1; TCCR0B=0x04; TCNT0=0x00; OCR0A=0x00; OCR0B=0x00; // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: 31.250 kHz // Mode: Normal top=FFFFh // OC1A output: Discon. // OC1B output: Discon. // Noise Canceler: Off // Input Capture on Falling Edge // Timer 1 Overflow Interrupt: Off // Input Capture Interrupt: Off // Compare A Match Interrupt: Off // Compare B Match Interrupt: Off TCCR1A=0x00; TCCR1B=0x04; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; // Timer/Counter 2 initialization // Clock source: System Clock // Clock value: 31.250 kHz // Mode: Phase correct PWM top=FFh // OC2A output: Disconnected // OC2B output: Non-Inverted PWM ASSR=0x00; TCCR2A=0x21; TCCR2B=0x06; TCNT2=0x80; OCR2A=0x00; OCR2B=0x00; // External Interrupt(s) initialization // INT0: On // INT0 Mode: Falling Edge // INT1: Off // Interrupt on any change on pins PCINT0-7: Off // Interrupt on any change on pins PCINT8-14: Off // Interrupt on any change on pins PCINT16-23: Off EICRA=0x02; EIMSK=0x01; EIFR=0x01; PCICR=0x00; // Timer/Counter 0 Interrupt(s) initialization TIMSK0=0x00; // Timer/Counter 1 Interrupt(s) initialization TIMSK1=0x00; // Timer/Counter 2 Interrupt(s) initialization TIMSK2=0x00; // USART initialization // Communication Parameters: 8 Data, 1 Stop, No Parity // USART Receiver: Off // USART Transmitter: On // USART0 Mode: Asynchronous // USART Baud Rate: 9600 UCSR0A=0x00; UCSR0B=0x08; UCSR0C=0x06; UBRR0H=0x00; UBRR0L=0x33; // Analog Comparator initialization // Analog Comparator: Off // Analog Comparator Input Capture by Timer/Counter 1: Off ACSR=0x80; ADCSRB=0x00; // Global enable interrupts #asm("sei") btn=1; pos=0; PANEL_ENABLE = 1; state = 1; OCR0A=0x80; OCR0B=0x80; OCR2B=0x80; weight[0]=85; weight[1]=85; weight[2]=85; lum = 32; printf("Starting init.\n"); ret=init_mouse(); printf("init done %d\n",ret); while (1){ ret = update_mouse_pos(); if(ret){ if(ret & 0x02){ if(LMB_PRESSED){ weight[0]=85; weight[1]=85; weight[2]=85; lum = 32; }else{ state = 1-state; if(state){ PANEL_ENABLE=1; LED_R = 0; LED_G = 1; }else{ PANEL_ENABLE=0; LED_R = 1; LED_G = 0; } } } action = classify_movement(&magnitude); switch(action){ case LUM: if(magnitude>0){ if((MAXLUM - lum) > magnitude) lum += magnitude; else lum = MAXLUM; }else{ if(lum > abs(magnitude)) lum += magnitude; else lum=0; } break; case RB: if(magnitude>0){ if(weight[BLUE] > magnitude){ weight[RED] += magnitude; weight[BLUE] -= magnitude; }else{ weight[RED] += weight[BLUE]; weight[BLUE] = 0; } }else{ if(weight[RED] > abs(magnitude)){ weight[RED] += magnitude; weight[BLUE] -= magnitude; }else{ weight[BLUE] += weight[RED]; weight[RED] = 0; } } break; case BG: if(magnitude>0){ if(weight[BLUE] > magnitude){ weight[GREEN] += magnitude; weight[BLUE] -= magnitude; }else{ weight[GREEN] += weight[BLUE]; weight[BLUE] = 0; } }else{ if(weight[GREEN] > abs(magnitude)){ weight[GREEN] += magnitude; weight[BLUE] -= magnitude; }else{ weight[BLUE] += weight[GREEN]; weight[GREEN] = 0; } } break; case RG: if(magnitude>0){ if(weight[RED] > magnitude){ weight[GREEN] += magnitude; weight[RED] -= magnitude; }else{ weight[GREEN] += weight[RED]; weight[RED] = 0; } }else{ if(weight[GREEN] > abs(magnitude)){ weight[GREEN] += magnitude; weight[RED] -= magnitude; }else{ weight[RED] += weight[GREEN]; weight[GREEN] = 0; } } break; } wmax = weight[RED]; if(weight[GREEN]>wmax) wmax = weight[GREEN]; if(weight[BLUE]>wmax) wmax = weight[BLUE]; wr = ((4ul*lum)*weight[RED])/((unsigned long)wmax); wg = ((4ul*lum)*weight[GREEN])/((unsigned long)wmax); wb = ((4ul*lum)*weight[BLUE])/((unsigned long)wmax); vr = wr; vg = wg; vb=wb; if(vr>255) vr=255; if(vg>255) vg=255; if(vb>255) vb=255; // Channel brightness adjusted via PWM. OCR0A = vr; OCR2B = vb; OCR0B = vg; printf("l=%d r=%d, g=%d b=%d\n",lum,weight[RED],weight[GREEN], weight[BLUE]); delay_ms(10); printf("m=%d R=%ld r=%d\n",wmax,wr, vr); }else{ delay_ms(1); } } }