/* PING runs on an ATMEGA8 with 16MHz, program is written in AVR-GCC * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return Niklas Roy * ---------------------------------------------------------------------------- As usual: Sorry for too less coments and crappy coding skills */ #include #include #include #include #include #include volatile uint8_t ping_graphics[8][19]={ {1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,1,0,1,0}, {1,0,0,1,0,0,0,1,0,0,1,0,1,0,0,0,0,1,0}, {1,0,0,1,0,1,0,1,0,0,1,0,1,0,0,0,0,1,0}, {1,1,1,1,0,1,0,1,0,0,1,0,1,0,1,1,0,1,0}, {1,0,0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0}, {1,0,0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,0}, {1,0,0,0,0,1,0,1,0,0,1,0,1,1,1,1,0,1,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, }; volatile uint8_t subtext_graphics[6][72]={ // A U G M E N T E D P I X E L {0,1,1,1,1,0,1,0,0,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,0,0,0,0,1,1,1,1,0,1,0,1,0,0,1,0,1,1,1,1,0,1,0,0,0,0}, {0,1,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,1,0,1,0,0,1,0,1,0,0,0,0,1,0,0,0,0}, {0,1,1,1,1,0,1,0,0,1,0,1,0,1,1,0,1,0,1,0,1,0,1,1,1,0,0,1,0,0,1,0,0,0,1,0,0,0,1,1,1,0,0,1,0,0,1,0,0,0,1,1,1,1,0,1,0,0,1,1,0,0,1,1,1,0,0,1,0,0,0,0}, {0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1,0,0,0,0}, {0,1,0,0,1,0,1,1,1,1,0,1,1,1,1,0,1,0,0,0,1,0,1,1,1,1,0,1,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0,1,1,1,0,0,0,0,1,0,0,0,0,1,0,1,0,0,1,0,1,1,1,1,0,1,1,1,1,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // 1 1 2 3 4 5 6 7 // 0 0 0 0 0 0 0 // | | | | | | | | | }; float slow_count=0; float sin_result; float sin_result2; volatile uint8_t sin_shift=0; volatile uint8_t scroll_count; volatile uint16_t video_line=0; volatile uint8_t ball_x=20; //0-110 volatile uint16_t ball_y=100; //50-290 volatile int8_t speed_x=1; volatile int8_t speed_y=2; volatile uint8_t obstacle[]={0,0,0,0,0,0,0,0}; volatile uint8_t end_of_image=0; volatile uint8_t display_thresh=0; volatile uint8_t start_screen=1; int8_t ball_direction; int8_t beep_cycle=0;; //////////////////////////////////////////////////////////////// MAIN ///////////////////////////// int main(void) { //IO DDRB = 0b00000010; // b1:sound output DDRC = 0b00000001; // c0:via 1k to video signal DDRD = 0b00000000; // d2,d3 sync signal inputs //Pull Up's / Outputs PORTB= 0b00000000; // PORTC= 0b00000000; // PORTD= 0b00100000; // d5:button TCCR1A=0b01000000; // configure pwm output on pb1 (sound) TCCR1B=0b00001011; MCUCR=0b00000110; //INT0 & INT1 generate interrupt requests GICR= 0b11000000; //hardware interrupt INT0&1 enable sei(); //switch on global interrupts while(1) { if (end_of_image){ //will be executed when whole image is drawn end_of_image=0; if ( PIND & (1<<5 ) ) { //check button display_thresh=0; //no button pushed }else{ display_thresh++; //button pushed if (display_thresh>25)display_thresh=25; start_screen=0; TCCR1A=0b10000001; // configure pwm output on pb1 (sound) TCCR1B=0b00000010; } if(start_screen){ //calculate start screen animation scroll_count++; slow_count++; sin_result=slow_count; sin_result/=16; sin_result=sin(sin_result); sin_result+=1; sin_result*=60; sin_result2=slow_count*10; sin_result2=sin(sin_result2); sin_result2+=1; sin_result2*=5; sin_shift=sin_result; OCR1A=(sin_result+sin_result2)*8+20; //sound at start animation TCNT1=0; }else{ //no start screen: calculate game logics instead uint8_t max_val=0; uint8_t max_pos=10; for (uint8_t i=0;i<8;i++){ //find darkest obstacle if(obstacle[i]>max_val){ max_val=obstacle[i]; max_pos=i; } } OCR1A=OCR1A>>1; //switch off previous sound switch (max_pos){ //new direction is opposite from darkest obstacle case 4: speed_x=-1; speed_y=-2; OCR1A=21; //sound break; case 5: speed_x=0; speed_y=-2; OCR1A=22; //sound break; case 6: speed_x=1; speed_y=-2; OCR1A=23; //sound break; case 7: speed_x=1; speed_y=0; OCR1A=24; //sound break; case 0: speed_x=1; speed_y=2; OCR1A=25; //sound break; case 1: speed_x=0; speed_y=2; OCR1A=26; //sound break; case 2: speed_x=-1; speed_y=2; OCR1A=27; //sound break; case 3: speed_x=-1; speed_y=0; OCR1A=28; //sound break; } //move ball ball_x+=speed_x; if (ball_x==255){ //ball out left ball_x=93; }else if(ball_x>93){ //ball out right ball_x=0; } ball_y+=speed_y; if (ball_y>275) { //bounce bottom speed_y=-2; ball_y=275; OCR1A=33; //sound } if (ball_y<65) { //bounce top speed_y=2; ball_y=65; OCR1A=33; //sound } for (uint8_t i=0;i<8;i++){ //reset obstacle detection obstacle[i]=0; } } } } } ISR(INT1_vect) // interrupt routine - new video image { video_line=0; } ISR(INT0_vect) // interrupt routine - new video line { video_line++; uint16_t temp_video_line=video_line; uint8_t temp_ball_x=ball_x; uint16_t temp_ball_y=ball_y; uint8_t temp_top_left_obstacle=obstacle[0]; uint8_t temp_top_mid_obstacle=obstacle[1]; uint8_t temp_top_right_obstacle=obstacle[2]; uint8_t temp_right_obstacle=obstacle[3]; uint8_t temp_bot_right_obstacle=obstacle[4]; uint8_t temp_bot_mid_obstacle=obstacle[5]; uint8_t temp_bot_left_obstacle=obstacle[6]; uint8_t temp_left_obstacle=obstacle[7]; uint8_t i; if (start_screen){//------------------------------------------------ start screen if (temp_video_line>=45&&temp_video_line<230){ _delay_us(16); uint8_t screen_y=(temp_video_line-45-sin_shift)/8; if (screen_y>7)screen_y=7; for (uint8_t i=0;i<19;i++){ PORTC=ping_graphics[screen_y][i]; //draw 'PING' } }else if (temp_video_line>230&&temp_video_line<260){ _delay_us(2); uint8_t screen_y=(temp_video_line-230)/4; if (screen_y>5)screen_y=5; for (uint8_t i=0;i<50;i++){ PORTC=subtext_graphics[screen_y][i]; //draw 'AUGMENTED' } }else if (temp_video_line>260&&temp_video_line<290){ _delay_us(2); uint8_t screen_y=(temp_video_line-260)/4; if (screen_y>5)screen_y=5; _delay_us(12.5); for (uint8_t i=50;i<72;i++){ PORTC=subtext_graphics[screen_y][i]; //draw 'PIXEL' } }else if (temp_video_line==290){ end_of_image=1; } }else{//------------------------------------------------------------ normal_game if(temp_video_line>60&&temp_video_line<290){ if(temp_video_line<65){ //top playfield line _delay_us(4.5); PORTC=0b00000001; _delay_us(41); _delay_us(.5); PORTC= 0b00000000; }else if(temp_video_line>285){ //bottom playfield line _delay_us(4); PORTC=0b00000001; _delay_us(41); _delay_us(.5); PORTC= 0b00000000; }else if(display_thresh>24){ //display brightnes threshold for adjustment _delay_us(2); for (i=0;i<74;i++){ if ((ACSR&(1<temp_ball_y-5&&temp_video_linetemp_ball_y&&temp_video_linetemp_ball_y+10){ //video lines below ball for (i=0;i