#include #include #pragma regalloc- #define maxkeys 16 #define K_INIT 0 #define NO_CHAR 1 #define MAYBE_CHAR 96 #define YES_CHAR 2 #define YES_CHAR_REL 3 //timeout values for each task #define t1 50 //50ms #define t2 255 char screen[512]; int x; char num; char xwinner, owinner; //Key pad input state machine variables unsigned char STATE, PSTATE; unsigned char maybe; unsigned char key, butnum; char ascii_digit; unsigned char reload, time1, time2; unsigned char j; int i; //key pad scan table flash unsigned char keytbl[16] = { 0xee, 0xed, 0xeb, 0xe7, 0xde, 0xdd, 0xdb, 0xd7, 0xbe, 0xbd, 0xbb, 0xb7, 0x7e, 0x7d, 0x7b, 0x77}; flash char ascii_table[16] = { '1', '4', '7', '#', '2', '5', '8', '0', '3', '6', '9', '*', 'A', 'B', 'C', 'D'}; unsigned char posx[9]; //player occupies a square array element=1 unsigned char poso[9]; unsigned char xwin, owin; //whether or not someone won and how char px; //whose turn it is //the task subroutines void keypad(void); //keypad scan routine void taken(char); //check if a square is taken void draw_line(char); //draw-line for winner void task1(void); //Keypad state machine void task2(void); //Check for winner void init(void); //all the usual mcu stuff /***Letter and Number Symbol Library***/ void draw_A(int); void draw_B(int); void draw_C(int); void draw_D(int); void draw_E(int); void draw_F(int); void draw_G(int); void draw_H(int); void draw_I(int); void draw_J(int); void draw_K(int); void draw_L(int); void draw_M(int); void draw_N(int); void draw_O(int); void draw_P(int); void draw_Q(int); void draw_R(int); void draw_S(int); void draw_T(int); void draw_U(int); void draw_V(int); void draw_W(int); void draw_X(int); void draw_Y(int); void draw_Z(int); void draw_0(int); void draw_1(int); void draw_2(int); void draw_3(int); void draw_4(int); void draw_5(int); void draw_6(int); void draw_7(int); void draw_8(int); void draw_9(int); void draw_AMP(int); void draw_num(char, int); //display functions void display_opening(void); void display_board(void); void display_ending(void); void black_screen(void); void white_screen(void); #asm .equ PORTD=0x12 ;sync .equ PORTC=0x15 ;display .equ PORTB=0x18 ;used for debugging #endasm #pragma savereg- //********************************************************** //timer 0 overflow ISR interrupt [TIM0_OVF] void timer0_overflow(void) { #asm in r14, SREG sei #endasm //reload to force 1 mSec overflow TCNT0=reload; //Decrement the three times if they are not already zero if (time1>0) --time1; if (time2>0) --time2; #asm out SREG, r14 #endasm } //********************************************************** //timer 1 compare-match A ISR interrupt [TIM1_COMPA] void cmpA_overflow(void){ #asm in r14, SREG ;store state tst r18 ;tst frame number ldi r19, 0x00 out PORTC, r19 ;display should be off while syncing out PORTD, r19 ;clear sync breq vsync nop hsync: ;sync has already been cleared ldi r20, 1 rcall DELAY ;delay 3us tst r18 nop nop ldi r19, 0x20 out PORTD, r19 ;set sync tst r18 rjmp display ;jump to display info ;ideally vsync would be inverted hsync (pulse happening at same time) ;but this is easier and it works... vsync: ldi r18, 0xff ;total # of lines ldi r20, 0x08 rcall DELAY ;10us delay ldi r19, 0x20 out PORTD, r19 ;set sync ldi r20, 2 in r15, SREG rcall DELAY ;delay 4us out SREG, r15 ldi r19, 0x00 out PORTD, r19 ldi r20, 0x2e in r15, SREG rcall DELAY ;delay to make vsync 64us total out SREG, r15 tst r21 breq exit_int dec r21 rjmp vsync ;should vsync 5 times and then exit hsync_ext: dec r18 ;dec frame number exit_int: ldi r21, 0x05 ;#of vsyncs out SREG, r14 ;restore state reti ;delays for 1us DELAY1: ;3 cycles to get in ret ;8 ;DELAY -- can delay for 2us+ in 1us steps ; -- param passed via r20 so delay is 2+r20 us DELAY: ;delay time = 16 + 8*r20 (cycles) dloop: ;4 cycles to get in tst r20 ;each interation + 8 cycles breq dexit dec r20 nop nop nop rjmp dloop dexit: ;3 cycles for partial loop nop nop nop nop nop ;5 nop ret ;16 cycle overhead nada: ;come here for pre-equalization mov r18, r9 ldi r19, 0x00 out PORTC, r19 ;clear display rjmp hsync_ext display: ;do this in the 8us delay and sync period mov r9, r18 subi r18, 0xe4 ;controls #of pre-eq pulses - shifts image down as imm decreases tst r18 brpl nada ;check whether its ok to display mov r18, r9 push r14 ;save state push r22 push r23 push r24 push r25 push r26 push r30 push r31 tst r5 ;dedicated register to ensure this happens once every 255 times ;(restart screen array after drawing entire screen) ;does not work cause it draws all of the above array, a bunch of ;black lines(1/2 screen), then goes back to top brne not_first ldi r30, low(_screen) ;load pointer if first time through ldi r31, high(_screen) mov r12, r30 ;store state to r12, r13 mov r13, r31 not_first: inc r5 mov r30, r12 ;restore Z (Z is stored in r12, r13 at end of display) mov r31, r13 ld r11, Z+ ;load next 8 bytes to regs ld r16, Z+ ld r17, Z+ ld r22, Z+ ld r23, Z+ ld r24, Z+ ld r25, Z+ ld r26, Z+ mov r12, r30 ;store Z mov r13, r31 nop nop pixel: ;****byte0**** one pixel loop 0.5us lsl r11 ;shift left,check carry bit in r14, SREG ;cary bit is zero bit of SREG nop nop out PORTC, r14 ;set output lsl r11 ;shift again and repeat in r14, SREG nop nop out PORTC, r14 lsl r11 in r14, SREG nop nop out PORTC, r14 lsl r11 in r14, SREG nop nop out PORTC, r14 lsl r11 in r14, SREG nop nop out PORTC, r14 lsl r11 in r14, SREG nop nop out PORTC, r14 lsl r11 in r14, SREG nop nop out PORTC, r14 lsl r11 in r14, SREG nop nop out PORTC, r14 ;****byte1**** lsl r16 in r14, SREG nop nop out PORTC, r14 lsl r16 in r14, SREG nop nop out PORTC, r14 lsl r16 in r14, SREG nop nop out PORTC, r14 lsl r16 in r14, SREG nop nop out PORTC, r14 lsl r16 in r14, SREG nop nop out PORTC, r14 lsl r16 in r14, SREG nop nop out PORTC, r14 lsl r16 in r14, SREG nop nop out PORTC, r14 lsl r16 in r14, SREG nop nop out PORTC, r14 ;****byte2**** lsl r17 in r14, SREG nop nop out PORTC, r14 lsl r17 in r14, SREG nop nop out PORTC, r14 lsl r17 in r14, SREG nop nop out PORTC, r14 lsl r17 in r14, SREG nop nop out PORTC, r14 lsl r17 in r14, SREG nop nop out PORTC, r14 lsl r17 in r14, SREG nop nop out PORTC, r14 lsl r17 in r14, SREG nop nop out PORTC, r14 lsl r17 in r14, SREG nop nop out PORTC, r14 ;****byte3**** lsl r22 in r14, SREG nop nop out PORTC, r14 lsl r22 in r14, SREG nop nop out PORTC, r14 lsl r22 in r14, SREG nop nop out PORTC, r14 lsl r22 in r14, SREG nop nop out PORTC, r14 lsl r22 in r14, SREG nop nop out PORTC, r14 lsl r22 in r14, SREG nop nop out PORTC, r14 lsl r22 in r14, SREG nop nop out PORTC, r14 lsl r22 in r14, SREG nop nop out PORTC, r14 ;****byte4**** lsl r23 in r14, SREG nop nop out PORTC, r14 lsl r23 in r14, SREG nop nop out PORTC, r14 lsl r23 in r14, SREG nop nop out PORTC, r14 lsl r23 in r14, SREG nop nop out PORTC, r14 lsl r23 in r14, SREG nop nop out PORTC, r14 lsl r23 in r14, SREG nop nop out PORTC, r14 lsl r23 in r14, SREG nop nop out PORTC, r14 lsl r23 in r14, SREG nop nop out PORTC, r14 ;****byte5**** lsl r24 in r14, SREG nop nop out PORTC, r14 lsl r24 in r14, SREG nop nop out PORTC, r14 lsl r24 in r14, SREG nop nop out PORTC, r14 lsl r24 in r14, SREG nop nop out PORTC, r14 lsl r24 in r14, SREG nop nop out PORTC, r14 lsl r24 in r14, SREG nop nop out PORTC, r14 lsl r24 in r14, SREG nop nop out PORTC, r14 lsl r24 in r14, SREG nop nop out PORTC, r14 ;****byte6**** lsl r25 in r14, SREG nop nop out PORTC, r14 lsl r25 in r14, SREG nop nop out PORTC, r14 lsl r25 in r14, SREG nop nop out PORTC, r14 lsl r25 in r14, SREG nop nop out PORTC, r14 lsl r25 in r14, SREG nop nop out PORTC, r14 lsl r25 in r14, SREG nop nop out PORTC, r14 lsl r25 in r14, SREG nop nop out PORTC, r14 lsl r25 in r14, SREG nop nop out PORTC, r14 ;****byte7**** lsl r26 in r14, SREG nop nop out PORTC, r14 lsl r26 in r14, SREG nop nop out PORTC, r14 lsl r26 in r14, SREG nop nop out PORTC, r14 lsl r26 in r14, SREG nop nop out PORTC, r14 lsl r26 in r14, SREG nop nop out PORTC, r14 lsl r26 in r14, SREG nop nop out PORTC, r14 lsl r26 in r14, SREG nop nop out PORTC, r14 lsl r26 in r14, SREG nop nop out PORTC, r14 ;********turn off display for remainder of line ldi r20, 0x00 out PORTC, r20 ;****this redraws a line 4 times before loading next 8 bytes tst r10 ldi r20, 0x08 brne sub add r12, r20 adc r13, r7 sub: sub r12, r20 sbc r13, r7 ldi r20, 0x03 inc r10 and r10, r20 ;*** pop r31 ;restore state pop r30 pop r26 pop r25 pop r24 pop r23 pop r22 pop r14 rjmp hsync_ext #endasm } #pragma savereg+ void main(void){ init(); black_screen(); delay_us(5); display_opening(); //title screen while(1){ #asm sleep #endasm if (time1==0) task1(); if (time2==0) task2(); }//while }//main /************************************************* * TIC TAC TOE SHITS STARTS RIGHT HERE * *************************************************/ /***************************************** * TASK1 - KEYPAD DEBOUNCE STATE MACHINE * *****************************************/ void task1(void){ time1 = t1; switch(STATE){ case K_INIT: STATE = NO_CHAR; keypad(); break; case NO_CHAR: if(butnum ==0){ keypad(); STATE = NO_CHAR; } else{ maybe = butnum; keypad(); STATE = MAYBE_CHAR; } break; case MAYBE_CHAR: if (butnum == maybe){ maybe = 0; STATE = YES_CHAR; keypad(); } else{ keypad(); maybe = 0; STATE = NO_CHAR; } break; case YES_CHAR: delay_us(100); if (butnum == 0) STATE = YES_CHAR_REL; else{ keypad(); STATE = YES_CHAR; } break; case YES_CHAR_REL: taken(ascii_digit); STATE = NO_CHAR; break; } } /**************************** * TASK2 - CHECK FOR WINNER * *****************************/ void task2(void){ time2 = t2; //1s if(xwin > 0 || owin > 0){ black_screen(); delay_us(5); display_ending(); } } //Checks to see if square is occupied, then check for winner void taken(char blah) { switch(blah){ case '1': if(!posx[0] && !poso[0]){ if(px==1){ posx[0] = 1; draw_X(1); } else{ poso[0] = 1; draw_O(1); } } else{ if(px==1) //invalid button press. switch back to same player px = 0; else px = 1; } break; case '2': if(!posx[1] && !poso[1]){ if(px==1){//x turn posx[1] = 1; draw_X(4); } else{ poso[1] = 1; draw_O(4); } } else{ if(px==1) //invalid button press. switch back to same player px = 0; else px = 1; } break; case '3': if(!posx[2] && !poso[2]){ if(px==1){//x turn posx[2] = 1; draw_X(6); } else{ poso[2] = 1; draw_O(6); } } else{ if(px==1) //invalid button press. switch back to same player px = 0; else px = 1; } break; case '4': if(!posx[3] && !poso[3]){ if(px==1){//x turn posx[3] = 1; draw_X(81); } else{ poso[3] = 1; draw_O(81); } } else{ if(px==1) //invalid button press. switch back to same player px = 0; else px = 1; } break; case '5': if(!posx[4] && !poso[4]){ if(px==1){//x turn posx[4] = 1; draw_X(84); } else{ poso[4] = 1; draw_O(84); } } else{ if(px==1) //invalid button press. switch back to same player px = 0; else px = 1; } break; case '6': if(!posx[5] && !poso[5]){ if(px==1){//x turn posx[5] = 1; draw_X(86); } else{ poso[5] = 1; draw_O(86); } } else{ if(px==1) //invalid button press. switch back to same player px = 0; else px = 1; } break; case '7': if(!posx[6] && !poso[6]){ if(px==1){//x turn posx[6] = 1; draw_X(161); } else{ poso[6] = 1; draw_O(161); } } else{ if(px==1) //invalid button press. switch back to same player px = 0; else px = 1; } break; case '8': if(!posx[7] && !poso[7]){ if(px==1){//x turn posx[7] = 1; draw_X(164); } else{ poso[7] = 1; draw_O(164); } } else{ if(px==1) //invalid button press. switch back to same player px = 0; else px = 1; } break; case '9': if(!posx[8] && !poso[8]){ if(px==1){//x turn posx[8] = 1; draw_X(166); } else{ poso[8] = 1; draw_O(166); } } else{ if(px==1) //invalid button press. switch back to same player px = 0; else px = 1; } break; case 'A': //only switch players if there was a winner if(owin==0 && xwin==0){ if(px==1) px = 0; else px = 1; } display_board(); break; default: if(px==1) //invalid button press. switch back to same player px = 0; else px = 1; break; }//switch //changed players for each button pressed. if it was an invalid press //this will rechange players- i.e. no change if(px==1) px = 0; else px = 1; //check for a win... if(px==0){//if player x just pressed a button (if he did it was inverted above... //horizontal wins if(posx[0]&&posx[1]&&posx[2]){ xwin = 1; xwinner++;} else if(posx[3]&&posx[4]&&posx[5]){ xwin = 2; xwinner++;} else if(posx[6]&&posx[7]&&posx[8]){ xwin = 3; xwinner++;} //vertical wins else if(posx[0]&&posx[3]&&posx[6]){ xwin = 4; xwinner++;} else if(posx[1]&&posx[4]&&posx[7]){ xwin = 5; xwinner++;} else if(posx[2]&&posx[5]&&posx[8]){ xwin = 6; xwinner++;} //diagonal wins else if(posx[0]&&posx[4]&&posx[8]){ xwin = 7; xwinner++;} else if(posx[2]&&posx[4]&&posx[6]){ xwin = 8; xwinner++;} //no win else xwin = 0; } else{ if(poso[0]&&poso[1]&&poso[2]){ owin = 1; owinner++;} else if(poso[3]&&poso[4]&&poso[5]){ owin = 2; owinner++;} else if(poso[6]&&poso[7]&&poso[8]){ owin = 3; owinner++;} else if(poso[0]&&poso[3]&&poso[6]){ owin = 4; owinner++;} else if(poso[1]&&poso[4]&&poso[7]){ owin = 5; owinner++;} else if(poso[2]&&poso[5]&&poso[8]){ owin = 6; owinner++;} else if(poso[0]&&poso[4]&&poso[8]){ owin = 7; owinner++;} else if(poso[2]&&poso[4]&&poso[6]){ owin = 8; owinner++;} else owin = 0; } //draw the winners line if((owin||xwin)>0){ if(px==0) //backwards since player change already happend draw_line(xwin); else draw_line(owin); } } void keypad(void){ //standard keypad scan DDRB = 0x0f; PORTB = 0xf0; PSTATE = 1; //delay without blocking #asm nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop #endasm key = PINB; DDRB = 0xf0; PORTB = 0x0f; PSTATE = 2; //delay without blocking #asm nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop #endasm key = key | PINB; //find matching keycode in keytbl if (key != 0xff){ for (butnum=0; butnum 0) draw_X(1); else draw_O(1); draw_W(3); draw_I(4); draw_N(5); draw_S(6); draw_X(64); //draw_num(xwinner/10, 70); draw_num(xwinner, 71); draw_O(128); //draw_num(owinner/10, 134); draw_num(owinner, 135); draw_A(192); draw_C(195); draw_O(196); draw_N(197); draw_T(198); xwin = owin = 0; if (xwinner == 9) xwinner = 0; if (owinner == 9) owinner = 0; } void init(void){ DDRD = 0xff; PORTD = 0x20; DDRC = 0xff; PORTC = 0x00; //set up timer 0 reload=256-125; //value for 1 Msec TCNT0=reload; TIMSK=1; //turn on timer 0 overflow ISR TCCR0=3; //prescalar to 64 OCR1A = 512; //64us TCCR1A = 0x00; TCCR1B = 9; //prescale 1 clear on matchA TCNT1 = 0; TIMSK = TIMSK | 0x10; MCUCR = 0b01000000; //sleep enable; mode=idle //initialize the position maps for(i=0;i<9;i++){ posx[i] = 0; poso[i] = 0; } xwin = 0; owin = 0; xwinner = 0; owinner = 0; //init the task timers time1 = t1; time2 = t2; px = 1;//player X goes 1st STATE = K_INIT; PSTATE = 69; //initialize dedicated registers #asm ldi r18, 0x00 ;line counter mov r5, r18 ;need this if we use the branch shit instead of just above mov r7, r18 mov r9, r18 ldi r21, 0x05 ;#of vsyncs sei #endasm }