I have made the game pong using a pic 16F84 running @ 12MHz. The game Pong was the world's first video game in the early 70's, this is a modern version of it, made with a little bit less hardware than the original version. In my version, the video signal is generated in software. The only hardware used for the video generation is two resistors forming a 2-bit DA converter. Usually the video signal is generated in video games is created with a dedicated video chips, reading the image data from a graphics memory. In this project the video signal is calculated in real-time by the microprocessor as the electron beam sweeps over the screen. This page only describes the software, you can find schematics and description of the hardware here and for your service I also sell the parts for building the system here if you want to make sure you get the correct stuff, don't have a programmer or can't make PCBs yourself.
How to play the game.
The first screen is where you select how you want to play by moving the joystick: DOWN: Human vs. Human (H-H), LEFT: Human vs. Computer (H-C) or RIGHT: Computer vs. Computer (C-C). Start with FIRE. Unfortunately it is impossible to beat the computer, since there was not enough room to make the computer beatable. That makes the computer vs. computer game to play forever until someone reset the game using the reset switch. You start serving by pressing fire, it is also possible to change direction and speed of the ball using fire. The player who has the serve will get points. If the player with the serve miss the ball, then the serve goes over to the other player. When someone wins a game over picture will show and tell who won.
|Game menu. (Click to enlarge)||Game over screen. (Click to enlarge)|
With a processor performing 3MIPS, it is not easy to make a video signal in software. Each instruction performed takes 1/3 us. Each scan-line on the screen takes 64us, where 52us are visible, so it gives 52*3=156 visible clock cycles per line. Maximum resolution that can be obtained is 156 pixels in x-axis if the software is setting one pixel per clock (using for example only bcf and bsf), this would not give any game, so to make a ball bounce around more stuff has to be done, like loops and such. A loop quantifies the time to 3-clock pieces, giving a resolution of 52 pixels. (One could obtain a kind of 156pixels resolution with one or two offset nops, but the code to select this would eat to many clock cycles to do any good). In the pong game each line is treated different if there is a ball on it or not. If there is no ball on it, then all that has to be done is to show white color for a couple of clock cycles in the beginning or the end, depending on if the players are on this line or not. On a line with a ball, white should be shown in the middle for a couple of clock cycles, the delay before and after these white cycles are a function of the x position of the ball. The score is shown in the bottom of the screen, by loading the PORTB with the bitmap for the number and shift it out. In the main-screen, several letters are shown on each line. It is a little bit harder task, because the string has to be loaded and character bitmap has to be loaded for each letter. Doing all that and then showing it on the screen would make it possible to show only like three letters per line with a lot of spacing between them, which would be really ugly and useless as well. I solve this by calculating the bytes to shift out in one scan-line, and showing them the next, making it possible to show 8 chars per line. Unfortunately the characters are only drawn on every second line, but it is better than no characters at all. The text data is stored in the data eeprom, and the character bitmaps are stored in program eeprom as retlw tables.
So far I've only talked about the graphic generation. But there is more to it to get a video signal. All scan-lines first have a 4us-sync pulse, then black for 8us, then the 52us graphic comes. These horizontal sync-pulses makes the TV understand when a scan-line starts, but there is needed to send information about when a new picture starts too, it is called vertical sync, and is a special pattern that tells the TV that a new image is coming. There are two kinds of vertical sync, because the image is divided into two part images, showing even and odd lines, to get less flickering. In pong, the two images are identical, so the game is not using the full y-resolution possible, but it doesn't matter because it is way better than the x-resolution anyway, making the x-resolution the biggest problem.
The game stuff, like checking joystick and move stuff around, is taken care of in the first scan-lines, when no graphics is drawn. The sound is played during some free cycles close to the horizontal sync pulses, but not on all scan-lines, that's why the sound sounds very distorted.
Making this kind of software is mostly a clock-cycle-counting project, all timings are quite critical, so whatever paths the execution-flow of the program takes, it must take the same number of clock cycles. This is quite hard, and I've not managed to do this on all lines, so the image is a little bit bent in some places. (Most analog tv-sets fix this, but on some digital projectors it is more visible)
Schematics, layouts, source-code and hex-files are available in picpong.zip (71kB) it contains both PAL and NTSC versions, make sure you put the appropriate version into your chip. This file has now been updated with correct vsync since the original release (Credits go to Jesus Arias for finding the sync bug while writing his cool open source PIC emulator)
If you plan to try generating videosignals with PIC-chips you should try to use an
emulator, makes it much easier. There are poeople that have developed emulators for PIC
processors and have implemented plugins for emulating my hardware:
More info about video signals.
If you want to know more about video signals and about generating video signals in software using PIC's, check out some of these links:
PIC-Pong (C) Rickard Gunee. This is open source, use this at your own risk ! You may use the information on this page for your own projects as long as you refer to the original author (by name and link to authors homepage), don't do it for profit and don't hurt or harm anyone or anything with it. The author can not be held responsible for any damage caused by the information on this and related pages.