DotMatrixPong 1.0
|
00001 #ifndef F_CPU 00002 00003 #define F_CPU 1000000 00004 #endif 00005 00007 #define SCK PB4 00008 00009 #define OCK PB3 00010 00011 #define DS PB1 00012 00014 #define STATIC 0 00015 00016 #define SCROLLING 1 00017 00018 #include <avr/io.h> 00019 #include <util/delay.h> 00020 #include <avr/interrupt.h> 00021 #include <avr/pgmspace.h> 00022 #include <inttypes.h> 00023 00029 void clock_serial(); 00030 void clock_output(); 00031 void shift_high(); 00032 void shift_low(); 00033 void output(uint8_t*,uint8_t); 00034 void matrix_output(); 00035 void matrix_screen_pixel(uint32_t); 00036 00037 void adc_init(); 00038 void get_adcval(uint16_t *); 00039 uint8_t getkey(); 00040 00041 void timer_init(); 00042 00043 void clear_screen(); 00044 void start_game(); 00045 void game_failed(); 00046 void output_game(); 00047 void cursor_a_down(); 00048 void cursor_a_up(); 00049 void cursor_b_down(); 00050 void cursor_b_up(); 00051 00052 void next_r_ball(); 00053 uint8_t check_ball_coll(); 00054 00055 uint32_t rand(); 00056 00057 void output_text(char*,uint8_t); 00058 00060 uint8_t friendly_sm[5] PROGMEM = {0x0C,0x12,0x0,0x12,0x0}; 00062 uint8_t unfriendly_sm[5] PROGMEM = {0x12,0x0C,0x0,0x12,0x0}; 00064 uint8_t ansi[38][5] PROGMEM = { 00065 {0x12,0x12,0x1E,0x12,0x0C}, //A 00066 {0x0E,0x12,0x0E,0x12,0x0E}, //B 00067 {0x0C,0x02,0x02,0x02,0x0C}, //C 00068 {0x0E,0x12,0x12,0x12,0x0E}, //D 00069 {0x0E,0x02,0x0E,0x02,0x0E}, //E 00070 {0x0E,0x02,0x0E,0x02,0x02}, //F 00071 {0x1C,0x12,0x1A,0x02,0x1C}, //G 00072 {0x12,0x12,0x1E,0x12,0x12}, //H 00073 {0x0E,0x04,0x04,0x04,0x0E}, //I 00074 {0x06,0x08,0x08,0x08,0x0E}, //J 00075 {0x12,0x0A,0x06,0x0A,0x12}, //K 00076 {0x0E,0x02,0x02,0x02,0x02}, //L 00077 {0x12,0x12,0x12,0x1E,0x12}, //M 00078 {0x22,0x32,0x2A,0x26,0x22}, //N 00079 {0x0C,0x12,0x12,0x12,0x0C}, //O 00080 {0x04,0x04,0x1C,0x14,0x0C}, //P 00081 {0x14,0x0A,0x12,0x12,0x0C}, //Q 00082 {0x14,0x14,0x0C,0x14,0x0C}, //R 00083 {0x1C,0x10,0x08,0x04,0x1C}, //S 00084 {0x08,0x08,0x08,0x08,0x1C}, //T 00085 {0x1C,0x14,0x14,0x14,0x14}, //U 00086 {0x08,0x14,0x14,0x14,0x14}, //V 00087 {0x14,0x2A,0x2A,0x22,0x22}, //W 00088 {0x22,0x14,0x08,0x14,0x22}, //X 00089 {0x08,0x08,0x08,0x14,0x22}, //Y 00090 {0x1E,0x04,0x08,0x10,0x1E}, //Z 00091 {0x0E,0x0A,0x0A,0x0A,0x0E}, //0 00092 {0x1C,0x08,0x08,0x0C,0x08}, //1 00093 {0x1E,0x04,0x08,0x12,0x0C}, //2 00094 {0x0C,0x12,0x08,0x10,0x1E}, //3 00095 {0x08,0x08,0x0E,0x0A,0x0A}, //4 00096 {0x0E,0x08,0x0E,0x02,0x0E}, //5 00097 {0x0E,0x0A,0x0E,0x02,0x0E}, //6 00098 {0x08,0x08,0x0A,0x0A,0x0E}, //7 00099 {0x0E,0x0A,0x0E,0x0A,0x0E}, //8 00100 {0x0E,0x08,0x0E,0x0A,0x0E}, //9 00101 {0x00,0x40,0x00,0x40,0x00}, //: 00102 {0x00,0x00,0x00,0x00,0x00}}; // 00103 00104 00106 uint8_t cursor_a[5] = {0x0,0x1,0x1,0x0,0x0}; 00108 uint8_t cursor_b[5] = {0x0,0x00,0x40,0x40,0x00}; 00110 uint8_t ball[5] = {0x0,0x0,0x4,0x0,0x0}; 00111 00113 uint8_t screen_buffer_first[5]; 00115 uint8_t screen_buffer_second[5]; 00116 00118 volatile uint8_t ball_dir = 0; 00120 volatile uint16_t ball_timer = 0; 00122 uint8_t rand_timer = 0; 00124 uint8_t game_running = 0; 00126 volatile uint8_t game_failed_var = 0x0; 00128 uint8_t points_a = 0; 00130 uint8_t points_b = 0; 00131 00133 00146 int main() { 00147 uint8_t key = 0; 00148 DDRB = (1 << PB0) | (1 << PB1)| (1 << PB3) | (1 << PB4); 00149 00150 adc_init(); 00151 timer_init(); 00152 sei(); 00153 00154 clear_screen(); 00155 output_text("PONG",SCROLLING); 00156 start_game(); 00157 00158 while(1) { 00159 key = getkey(); 00160 if(game_failed_var == 0x1 || game_failed_var == 0x2) game_failed(); 00161 switch(key) { 00162 case 1: cursor_a_down(); break; 00163 case 2: cursor_a_up(); break; 00164 case 3: cursor_b_down(); break; 00165 case 4: cursor_b_up(); break; 00166 default: break; 00167 } 00168 } 00169 return 0; 00170 } 00171 00173 00181 void clock_serial() { 00182 PORTB |= (1 << SCK); 00183 PORTB &= ~(1 << SCK); 00184 } 00185 00187 00194 void clock_output() { 00195 PORTB |= (1 << OCK); 00196 PORTB &= ~(1 << OCK); 00197 } 00198 00200 00206 void shift_high() { 00207 PORTB |= (1 << DS); 00208 clock_serial(); 00209 } 00210 00212 00218 void shift_low() { 00219 PORTB &= ~(1 << DS); 00220 clock_serial(); 00221 } 00222 00224 00232 void output(uint8_t* in, uint8_t screen) { 00233 uint8_t i = 0; 00234 switch(screen) { 00235 case 1: for(i = 0; i < 5; i++) screen_buffer_first[i] = in[i]; break; 00236 case 2: for(i = 0; i < 5; i++) screen_buffer_second[i] = in[i]; break; 00237 default: break; 00238 } 00239 } 00240 00242 00256 void matrix_output() { 00257 uint8_t k,i,j,col,row = 0; 00258 uint32_t out = 0; 00259 00260 for(k = 0; k < 2; k++){ //Für beide Punktmatrix 00261 for(i = 0; i < 5; i++) { //Jede Spalte muss auf Punkte überprüft werden 00262 if(k == 0) row = screen_buffer_second[i]; //Erst die rechte Punktmatrix 00263 else row = screen_buffer_first[i]; //Dann die linke Punktmatrix 00264 for(j = 0; j < 7; j++) { //Dann wird jede Zeile auf ein Punkt überprüft 00265 if(row & 0x01) { //Wurde einer gefunden, 00266 out = (1 << j); //muss die jeweilige Zeile aktiviert werden 00267 out <<=5; //(Die Zeilen stehen in der Ausgabe 5 Bits weiter 00268 out |= (1 << i); //und es muss die jeweilige Spalte aktiviert werden 00269 out <<=1; //Welche erst ab Bit 1 anfangen 00270 if(k == 1) out <<= 16; //Für den linken Bildschirm muss das Ganze 16 Bits verschoben werden (aufgrund der Schieberegister) 00271 matrix_screen_pixel(out); 00272 } 00273 row >>=1; // Das nächste Bit wird überprüft 00274 } 00275 } 00276 } 00277 } 00278 00280 00291 void matrix_screen_pixel(uint32_t input) { 00292 uint8_t i = 0; 00293 00294 for(i = 0; i < 32; i++) { 00295 if((i < 26 && i > 16) || (i < 10)) { 00296 if(input & 0x80000000) shift_low(); 00297 else shift_high(); 00298 } 00299 else { 00300 if(input & 0x80000000) shift_high(); 00301 else shift_low(); 00302 } 00303 input <<= 1; 00304 } 00305 clock_output(); 00306 00307 PORTB &= ~(1 << DS); 00308 PORTB &= ~(1 << SCK); 00309 PORTB &= ~(1 << OCK); 00310 00311 } 00312 00314 00327 void adc_init() { 00328 uint16_t trash; 00329 ADMUX = (1 << MUX0); //PB2 00330 DIDR0 |= (1<<ADC0D); //PB2 (ADC0) 00331 ADCSRA = (1 << ADPS1) | (1 << ADPS0) | (1 << ADEN); //Division 8 00332 get_adcval(&trash); //First Conversion 00333 } 00334 00336 00342 void adc_start() { 00343 ADCSRA |= (1 << ADSC); 00344 } 00345 00347 00356 void get_adcval(uint16_t *val) { 00357 adc_start(); 00358 while(ADCSRA & (1 << ADSC)); 00359 *val = ADCW; 00360 } 00361 00363 00374 uint8_t getkey() { 00375 uint8_t key = 0; 00376 uint16_t adc_wert = 0; 00377 uint16_t zaehl = 0; 00378 while(1) { 00379 get_adcval(&adc_wert); 00380 zaehl++; 00381 if(adc_wert <= 50) { //Taste 4 von links 00382 key = 4; 00383 break; 00384 } 00385 else if(adc_wert <= 280 ) { //Taste 3 von links 00386 key = 3; 00387 break; 00388 } 00389 else if(adc_wert <= 540) { //Taste 2 von links 00390 key = 2; 00391 break; 00392 }// bis hier 00393 else if (adc_wert <= 790){ //Taste 1 von links 00394 key = 1; 00395 break; 00396 } 00397 00398 else if(adc_wert <= 1024) { //keine Taste 00399 key = 0; 00400 } 00401 if(zaehl >= 10) break; 00402 } 00403 rand_timer += zaehl+key; 00404 return key; 00405 } 00406 00408 00416 void timer_init() { 00417 TIMSK |= (1 << TOIE0); 00418 TCCR0B |= (1 << CS01); //Prescaler 8 00419 TCNT0 = 0x0; //Startwert 1 00420 } 00421 00423 00431 ISR(TIMER0_OVF_vect) { //Bildschirmausgabe 00432 ball_timer++; 00433 if(ball_timer % 2 && !(game_running)) return; //Bei der möglichen Textausgabe darf nur jedes zweite Mal der Interrupt vollständig ablaufen 00434 if(game_running) output_game(); 00435 matrix_output(); 00436 if((ball_timer % 10) == 0) rand_timer++; 00437 if(ball_timer >= 100 && game_running) { 00438 ball_timer = 0; 00439 next_r_ball(); 00440 } 00441 } 00442 00444 00450 void clear_screen() { 00451 uint8_t i = 0; 00452 for(i = 0; i < 5; i++) { 00453 screen_buffer_second[i]= 0x0; 00454 screen_buffer_first[i] = 0x0; 00455 } 00456 } 00457 00459 00468 void start_game() { 00469 uint8_t i = 0; 00470 game_failed_var = 0x0; 00471 for(i = 0; i < 5; i++) { 00472 cursor_a[i] = 0x0; 00473 cursor_b[i] = 0x0; 00474 } 00475 cursor_a[1] = 0x1; 00476 cursor_a[2] = 0x1; 00477 cursor_b[2] = 0x40; 00478 cursor_b[3] = 0x40; 00479 for(i = 0; i < 5; i++) ball[i]= 0x0; 00480 ball[2]= 0x4; 00481 ball_dir = 0; 00482 game_running = 1; 00483 output_game(); 00484 } 00485 00487 00494 void output_game() { 00495 uint8_t i = 0; 00496 clear_screen(); 00497 for(i = 0; i < 5; i++) screen_buffer_second[i] |= cursor_a[i] | cursor_b[i] | ball[i]; 00498 } 00499 00501 00509 void cursor_a_down() { 00510 uint8_t i = 0; 00511 if(cursor_a[0]== 0x01) return; 00512 else { 00513 for(i = 0; i < 4; i++) cursor_a[i]= cursor_a[i+1]; 00514 cursor_a[4] = 0x0; 00515 } 00516 } 00517 00519 00527 void cursor_a_up() { 00528 uint8_t i = 0; 00529 if(cursor_a[4]== 0x01) return; 00530 else { 00531 for(i = 4; i > 0; i--) cursor_a[i]= cursor_a[i-1]; 00532 cursor_a[0]= 0x0; 00533 } 00534 } 00535 00537 00545 void cursor_b_down() { 00546 uint8_t i = 0; 00547 if(cursor_b[0] == 0x40) return; 00548 else { 00549 for(i = 0; i < 4; i++) cursor_b[i]= cursor_b[i+1]; 00550 cursor_b[4] = 0x0; 00551 } 00552 } 00553 00555 00563 void cursor_b_up() { 00564 uint8_t i = 0; 00565 if(cursor_b[4] == 0x40) return; 00566 else { 00567 for(i = 4; i > 0; i--) cursor_b[i] = cursor_b[i-1]; 00568 cursor_b[0] = 0x0; 00569 } 00570 } 00571 00573 00587 void next_r_ball() { 00588 uint8_t col = 5; 00589 uint8_t i = 0; 00590 00591 i = check_ball_coll(); 00592 00593 if(i != 0) { 00594 if(i % 2) { //Rechte Seite aufgeschlagen 00595 i = rand() % 4; 00596 if(i == 1) i = 0; 00597 } 00598 else { //Linke Seite aufgeschlagen 00599 i = rand() % 4; 00600 if(i == 0 || i == 1) i = 1; 00601 else i += 2; 00602 } 00603 ball_dir = i; 00604 } 00605 00606 for(i = 0; i < 5; i++) if(ball[i] != 0) col = i; 00607 00608 00609 switch(ball_dir) { 00610 00611 case 0x0: //links 00612 ball[col] <<= 1; 00613 break; 00614 case 0x1: //rechts 00615 ball[col] >>= 1; 00616 break; 00617 case 0x2: //links-hoch 00618 00619 if(col == 4) { ball_dir = 3; break; } 00620 ball[col+1] = ball[col] << 1; 00621 ball[col] = 0x0; 00622 col++; 00623 break; 00624 case 0x3: //links-runter 00625 if(col == 0) { ball_dir = 2; break; } 00626 ball[col-1] = ball[col] << 1; 00627 ball[col] = 0x0; 00628 col--; 00629 break; 00630 case 0x4: //rechts-hoch 00631 if(col == 4) { ball_dir = 5; break; } 00632 ball[col+1] = ball[col] >> 1; 00633 ball[col] = 0x0; 00634 col++; 00635 break; 00636 case 0x5: //rechts-runter 00637 if(col == 0) { ball_dir = 4; break; } 00638 ball[col-1] = ball[col] >> 1; 00639 ball[col] = 0x0; 00640 col--; 00641 break; 00642 default: 00643 break; 00644 00645 } 00646 if(ball[col] == 0x0 && game_failed_var == 0) game_failed_var = 0x2; //Bei A-Spieler raus 00647 if(ball[col] >= 0x80 && game_failed_var == 0) game_failed_var = 0x1; //Bei B-Spieler raus 00648 00649 return; 00650 00651 } 00652 00653 00655 00664 uint8_t check_ball_coll() { 00665 uint8_t temp_coll[5] = {0x0,0x0,0x0,0x0,0x0}; 00666 uint8_t col = 0; 00667 uint8_t i = 0; 00668 uint8_t col_point = 0; 00669 00670 for(i = 0; i < 5; i++) { 00671 temp_coll[i] |= cursor_a[i] | cursor_b[i]; 00672 if(ball[i] != 0) col = i; 00673 } 00674 00675 if( (temp_coll[col] << 1 ) & ball[col] && col == 2) col_point = 1;//Rechte Seite 00676 if( (temp_coll[col] >> 1 ) & ball[col] && col == 2) col_point = 2;//Linke Seite 00677 if( (temp_coll[col] << 1 ) & ball[col] && col < 2) col_point = 3; //Rechte Seite 00678 if( (temp_coll[col] >> 1 ) & ball[col] && col > 2) col_point = 4; //Linke Seite 00679 if( (temp_coll[col] << 1 ) & ball[col] && col < 2) col_point = 5; //Rechte Seite 00680 if( (temp_coll[col] >> 1 ) & ball[col] && col > 2) col_point = 6; //Linke Seite 00681 00682 return col_point; 00683 } 00684 00685 00687 00696 void game_failed() { 00697 uint8_t temp_show[5] = {0,0,0,0,0}; 00698 uint8_t i = 0; 00699 00700 game_running = 0; 00701 clear_screen(); 00702 00703 for(i = 0; i < 5; i++) temp_show[i] = pgm_read_byte(&unfriendly_sm[i]); 00704 output(temp_show,2); 00705 _delay_ms(100); 00706 clear_screen(); 00707 00708 switch(game_failed_var) { 00709 case 0x1: points_a++; break; //A hat ein Punkt gemacht 00710 case 0x2: points_b++; break; //B hat ein Punkt gemacht 00711 default: break; 00712 } 00713 00714 for(i = 0; i < 5; i++) temp_show[i] = pgm_read_byte(&ansi[game_failed_var % 2][i]); 00715 00716 output(temp_show,2); 00717 _delay_ms(100); 00718 00719 clear_screen(); 00720 for(i = 0; i < 5; i++) temp_show[i] = pgm_read_byte(&ansi[26+points_a][i]); 00721 for(i = 0; i < 5; i++) temp_show[i] |= pgm_read_byte(&ansi[36][i]); 00722 output(temp_show,1); 00723 for(i = 0; i < 5; i++) temp_show[i] = pgm_read_byte(&ansi[26+points_b][i]); 00724 output(temp_show,2); 00725 00726 _delay_ms(150); 00727 00728 if(points_a == 9) { 00729 clear_screen(); 00730 output_text("A WIN",SCROLLING); 00731 points_a = points_b = 0; 00732 } 00733 if(points_b == 9) { 00734 clear_screen(); 00735 output_text("B WIN",SCROLLING); 00736 points_a = points_b = 0; 00737 } 00738 00739 start_game(); 00740 00741 } 00742 00744 00754 uint32_t rand() { 00755 return (ball_timer - rand_timer); 00756 } 00757 00759 00781 void output_text(char* text,uint8_t func) { //Optimierung 00782 uint8_t letter = 0,i,k,j = 0; 00783 uint8_t temp_buff_1[5] = {0,0,0,0,0}; 00784 uint8_t temp_buff_2[5] = {0,0,0,0,0}; //Jedes Byte bildet eine Zeile, die Bits die Spalten 00785 volatile uint8_t text_buffer[6][5] = {0}; 00786 00787 00788 while(*text) { //Text vom Flash in RAM puffern 00789 if(*text == 32) *text = 65+37; 00790 for(i = 0; i < 5; i++) text_buffer[letter][i] = pgm_read_byte(&ansi[(*text)-65][i]); 00791 letter++; 00792 text++; 00793 if(letter > 5) break; 00794 } 00795 00796 if(func == SCROLLING) { 00797 for(j = 0; j < (14 +(4*letter)); j++) { //Zwei Matrizen mit a 7 Spalten + die Anzahl der Pixel der Zeichen die außerhalb des Bildschirms starten 00798 for(i = 0; i < 5; i++) { //Jede Zeile wird berechnet, es gibt 5 Zeilen und 7 Spalten 00799 for(k = 0; k < letter; k++) { //Jeder Pixel jedes Zeichens kommt in direkt zusammen in eine Zeile 00800 if(j+1 > k*5) temp_buff_1[i] |= text_buffer[k][i] << 5 >> j-(k*5); //Rechts-Shift für 4 Pixel Zeichenabstand, Links-Shift zum scrollen 00801 if(j > (k*5)+7) temp_buff_2[i] |= text_buffer[k][i] << 5 >> j-(k*5)-7; //Sobald j < 7, Ausgabe auch auf andere Matrix erweitern 00802 } 00803 } 00804 output(temp_buff_1,2); //Ausgabe 00805 output(temp_buff_2,1); 00806 for(i = 0; i < 5; i++) { //Für den nächsten Scroll-Schritt, Puffer leeren 00807 temp_buff_1[i] = 0x0; 00808 temp_buff_2[i] = 0x0; 00809 } 00810 } 00811 } 00812 00813 if(func == STATIC) { //Baustelle 00814 for(i = 0; i < 5; i++) { 00815 for(k = 0; k < letter; k++) { 00816 temp_buff_1[i] |= text_buffer[k][i] << 5+(4*k) >> 14; 00817 temp_buff_2[i] |= text_buffer[k][i] << 5+(4*k) >> 14-7; 00818 } 00819 } 00820 output(temp_buff_1,2); 00821 output(temp_buff_2,1); 00822 00823 } 00824 } 00825