//video gen //D.5 is sync:1000 ohm + diode to 75 ohm resistor //D.6 is video:330 ohm + diode to 75 ohm resistor #include #include //cycles = 63.625 * 8 Note NTSC is 63.55 //but this line duration makes each frame exactly 1/60 sec //which is nice for keeping a realtime clock #define lineTime 509 #define begin { #define end } #define ScreenTop 30 #define ScreenBot 230 #define T0reload 256-60 //NOTE that the first line of CHARs must be in registers! char syncON, syncOFF, v1, v2, v3, v4, v5, v6, v7, v8; int i,LineCount, time; char ballx, bally, dx, dy; char screen[800], t, ts[10], temp; flash char bitmap[13][8]={ //0 0b00000000, 0b00111000, 0b01000100, 0b01000100, 0b01000100, 0b01000100, 0b01000100, 0b00111000, //1 0b00000000, 0b00010000, 0b00110000, 0b01010000, 0b00010000, 0b00010000, 0b00010000, 0b01111100, //2 0b00000000, 0b00011100, 0b00100010, 0b00000010, 0b00000100, 0b00001000, 0b00010000, 0b00111110, //3 0b00000000, 0b00011100, 0b00100010, 0b00000010, 0b00011100, 0b00000010, 0b00100010, 0b00011100, //4 0b00000000, 0b00001110, 0b00010010, 0b00100010, 0b00111111, 0b00000010, 0b00000010, 0b00000010, //5 0b00000000, 0b00111100, 0b00100000, 0b00100000, 0b00011100, 0b00000010, 0b00000010, 0b00111100, //6 0b00000000, 0b00010000, 0b00100000, 0b00100000, 0b00111100, 0b00100010, 0b00100010, 0b00011100, //7 0b00000000, 0b00111111, 0b00000001, 0b00000001, 0b00000010, 0b00000010, 0b00000100, 0b00000100, //8 0b00000000, 0b00011110, 0b00100001, 0b00100001, 0b00011110, 0b00100001, 0b00100001, 0b00011110, //9 0b00000000, 0b00011110, 0b00100001, 0b00100001, 0b00011110, 0b00000001, 0b00000001, 0b00000010, //C 0b00000000, 0b00011110, 0b00100000, 0b00100000, 0b00100000, 0b00100000, 0b00100000, 0b00011110, //U 0b00000000, 0b01000010, 0b01000010, 0b01000010, 0b01000010, 0b01000010, 0b01000010, 0b00111100, //E 0b00000000, 0b00111111, 0b00100000, 0b00100000, 0b00111111, 0b00100000, 0b00100000, 0b00111111}; //This is the sync generator. It MUST be entered from //sleep mode to get accurate timing of the sync pulses //At 8 MHz, all of the sync logic fits in the 5 uSec sync //pulse interrupt [TIM1_COMPA] void t1_cmpA(void) begin //start the Horizontal sync pulse PORTD = syncON; //count timer 0 at 1/usec TCNT0=0; //update the curent scanline number LineCount ++ ; //begin inverted (Vertical) synch after line 247 if (LineCount==248) begin syncON = 0b00100000; syncOFF = 0; end //back to regular sync after line 250 if (LineCount==251) begin syncON = 0; syncOFF = 0b00100000; end //start new frame after line 262 if (LineCount==263) begin LineCount = 1; end //end sync pulse PORTD = syncOFF; end // put a character on the screen // x-cood must be on divisible by 8 x position void video_putchar(char x, char y, char c) begin i=((int)x>>3) + ((int)y<<3) ; screen[i] = bitmap[c][0]; screen[i+8] = bitmap[c][1]; screen[i+16] = bitmap[c][2]; screen[i+24] = bitmap[c][3]; screen[i+32] = bitmap[c][4]; screen[i+40] = bitmap[c][5]; screen[i+48] = bitmap[c][6]; screen[i+56] = bitmap[c][7]; end // set up the ports and timers void main(void) begin //init timer 1 to generate sync OCR1A = lineTime; //One NTSC line TCCR1B = 9; //full speed; clear-on-match TCCR1A = 0x00; //turn off pwm and oc lines TIMSK = 0x10; //enable interrupt T1 cmp //init ports DDRD = 0xf0; //video out and switches //D.5 is sync:1000 ohm + diode to 75 ohm resistor //D.6 is video:330 ohm + diode to 75 ohm resistor //init timer 0 to 1/uSec TCCR0 = 2; //initialize synch constants LineCount = 1; syncON = 0b00000000; syncOFF = 0b00100000; //side lines for (i=0;i<799;i=i+8) begin screen[i]=0b10000000; screen[i+7]=0b00000001; end //top line & bottom lines for (i=0;i<8;i++) begin screen[i]=0b11111111; screen[i+792]=0b11111111; screen[i+88]=0b11111111; screen[i+712]=0b11111111; end //initial ball to middle of screen ballx=32; bally=50; dx = 1; dy = 2; //The following odd construction //sets exactly one bit at the x,y location i=((int)ballx>>3) + ((int)bally<<3) ; screen[i] = 1<<(7-(ballx & 0x7)) ; //init software timer t=0; time=0; //enable sleep mode MCUCR = 0b01000000; #asm ("sei"); //The following loop executes once/video line during lines //1-230, then does all of the frame end processing while(1) begin //precompute pixel index for next line if (LineCount=ScreenTop) begin //left-shift 3 would be individual lines // <<2 means line-double the pixels //The 0xfff8 truncates the odd line bit i=(LineCount-ScreenTop)<<2 & 0xfff8;; end //stall here until next line starts //sleep enable; mode=idle //use sleep to make entry into sync ISR uniform time #asm ("sleep"); //Put code here to execute once/line //During the active portion of a line; //--TCNT1 goes from about 130 to about 480 //--Usable lines 1 to about 240 if (LineCountScreenTop) begin //load the pixels into registers v1 = screen[i]; v2 = screen[i+1]; v3 = screen[i+2]; v4 = screen[i+3]; v5 = screen[i+4]; v6 = screen[i+5]; v7 = screen[i+6]; v8 = screen[i+7]; //now blast them out to the screen PORTD.6=v1 & 0b10000000; PORTD.6=v1 & 0b01000000; PORTD.6=v1 & 0b00100000; PORTD.6=v1 & 0b00010000; PORTD.6=v1 & 0b00001000; PORTD.6=v1 & 0b00000100; PORTD.6=v1 & 0b00000010; PORTD.6=v1 & 0b00000001; PORTD.6=v2 & 0b10000000; PORTD.6=v2 & 0b01000000; PORTD.6=v2 & 0b00100000; PORTD.6=v2 & 0b00010000; PORTD.6=v2 & 0b00001000; PORTD.6=v2 & 0b00000100; PORTD.6=v2 & 0b00000010; PORTD.6=v2 & 0b00000001; PORTD.6=v3 & 0b10000000; PORTD.6=v3 & 0b01000000; PORTD.6=v3 & 0b00100000; PORTD.6=v3 & 0b00010000; PORTD.6=v3 & 0b00001000; PORTD.6=v3 & 0b00000100; PORTD.6=v3 & 0b00000010; PORTD.6=v3 & 0b00000001; PORTD.6=v4 & 0b10000000; PORTD.6=v4 & 0b01000000; PORTD.6=v4 & 0b00100000; PORTD.6=v4 & 0b00010000; PORTD.6=v4 & 0b00001000; PORTD.6=v4 & 0b00000100; PORTD.6=v4 & 0b00000010; PORTD.6=v4 & 0b00000001; PORTD.6=v5 & 0b10000000; PORTD.6=v5 & 0b01000000; PORTD.6=v5 & 0b00100000; PORTD.6=v5 & 0b00010000; PORTD.6=v5 & 0b00001000; PORTD.6=v5 & 0b00000100; PORTD.6=v5 & 0b00000010; PORTD.6=v5 & 0b00000001; PORTD.6=v6 & 0b10000000; PORTD.6=v6 & 0b01000000; PORTD.6=v6 & 0b00100000; PORTD.6=v6 & 0b00010000; PORTD.6=v6 & 0b00001000; PORTD.6=v6 & 0b00000100; PORTD.6=v6 & 0b00000010; PORTD.6=v6 & 0b00000001; PORTD.6=v7 & 0b10000000; PORTD.6=v7 & 0b01000000; PORTD.6=v7 & 0b00100000; PORTD.6=v7 & 0b00010000; PORTD.6=v7 & 0b00001000; PORTD.6=v7 & 0b00000100; PORTD.6=v7 & 0b00000010; PORTD.6=v7 & 0b00000001; PORTD.6=v8 & 0b10000000; PORTD.6=v8 & 0b01000000; PORTD.6=v8 & 0b00100000; PORTD.6=v8 & 0b00010000; PORTD.6=v8 & 0b00001000; PORTD.6=v8 & 0b00000100; PORTD.6=v8 & 0b00000010; PORTD.6=v8 & 0b00000001; PORTD.6=0 ; end //The following code executes during the vertical blanking //Code here can be as long as 63 uSec/line //For a total of 30 lines x 63.5 uSec/line x 8 cycles/uSec // Every 60 uSec or so, you should insert a "sleep" //command so that the timer 1 ISR happens at a regular interval, //but it may not matter to most TVs if (LineCount==231) begin //erase old ball i=((int)ballx>>3) + ((int)bally<<3) ; temp = screen[i]; screen[i] = temp ^ (1<<(7-(ballx & 0x7))); //get new x ballx = ballx + dx ; if (ballx>61) dx = -1; if (ballx<2) dx = 1; //if (PIND.0==0) dx=dx*2; //get new y bally = bally + dy ; if (bally>86) dy = -1; if (bally<14) dy = 1; //if (PIND.1==0) dy=dy*2; // write new ball i=((int)ballx>>3) + ((int)bally<<3) ; temp = screen[i]; screen[i] = temp | (1<<(7-(ballx & 0x7))); // #asm ("sleep"); if (t++ > 59) begin t=0; time++; //Print "CU-ECE476" video_putchar(0,2,10); video_putchar(1*8,2,11); video_putchar(2*8,2,12); video_putchar(3*8,2,10); video_putchar(4*8,2,12); video_putchar(5*8,2,4); video_putchar(6*8,2,7); video_putchar(7*8,2,6); //make a dash i=(16>>3) + (6<<3) ; screen[i] = screen[i] | 1<<(7-(16 & 0x7)) ; //print the time sprintf(ts,"%05i",time); video_putchar(0,90,ts[0]-0x30); video_putchar(1*8,90,ts[1]-0x30); video_putchar(2*8,90,ts[2]-0x30); video_putchar(3*8,90,ts[3]-0x30); video_putchar(4*8,90,ts[4]-0x30); end end end //while end //main