Friday, April 27, 2018

Pong with the Basic Stamp and 1602a

As my first microcontroller project I decided to make a hand-held clone of the classic game Pong. Normally a graphical display would be required for this kind of project but I decided to take advantage of the custom character capabilities of the readily available 1602a LCD. The core of the project is the updated Basic Stamp from Coridium which based on the LPC11u37 ARM microcontroller, software for the stamp is written using an updated version of basic which is very similar to the first language I had learned, Qbasic.

The wiring diagram below shows how I connected the Basic Stamp to the LCD and three inputs needed to play the game. The pushbutton with the pullup resistor R1 is used to make selections and progress through the small menu system, R2 and R3 are the potentiometers that return a 0 to 3.3v signal used to control the paddles and change selections in the menu. The 10 digital outputs are used to interface with the LCD using it’s 8-bit parallel mode, R4 is a small trimpot used to set the contrast of the display. The contrast makes a big impact on how clearly the ball’s motion is visible but only needs to be set once. Finally I used a USB battery as the power source for the project, this takes care of charging the battery and providing a stable 5v supply for the microcontroller.

With the project wired on a breadboard I could start laying out my program, the flowchart below shows how the final version of the software turned out. After being powered on there are a few tasks that only need to be done once, like sending commands to the LCD to get it started and initializing all the global variables used in the game. After the PONG splash screen is shown the user can press the button and is presented with a choice between One and Two Player Modes, to get this input I look at the current value of the analog input for the right hand potentiometer. If the analog input is greater than half of 65472, the maximum input value, then One Player Mode will be selected when the button is pressed, if the analog input is lower than half the maximum value then Two Player Mode is selected.

For a single player the game now begins but for two players there is an additional step, picking the maximum score for the round. I wanted a range from 10 to 50 using increments of 5 and came up with the following line.
maxScore = ((((65472 - AD(1)) * 9) / 65480) * 5) + 10

"65472 – AD(1)" was used to reverse the direction of the input to make clockwise motion of the potentiometer increase the score, the result will still be a number from 0 to 65472. Multiplying the 0 to 65472 value by 9 and then taking the quotient of that value and 65480 (slightly larger than the maximum) results in integers from 0 to 8. Multiplying that integer value by 5 and adding it to 10 turns the 0 to 65472 input from the potentiometer into a 10 to 50 output with evenly spaced increments of 5.

Once the game has started in either One or Two Player Mode the logic is very similar. On every cycle of the game loop the position of the paddle(s) is updated by checking the value of the analog inputs and scaling them to a value from 0 to 16 (the usable height of my display) using the same method used to pick the max score. Next the ball’s position is updated by adding COS(BallDirection) * BallSpeed to the current X coordinate and SIN(BallDirection) * BallSpeed to the current Y coordinate, by storing the ball’s coordinates, direction and speed as floating point numbers I was able to get much smoother movement of the ball than if they were all integers. Instead of cogging from one pixel to the next the ball moves smoothly and it’s position is rounded to an integer only when being displayed on screen.

After being sent to the display the game checks if the ball should bounce off of any of the walls or paddles and adjusts the direction accordingly. In One Player Mode bounces off the far wall increase the players score, if the player misses the ball with their paddle they loose a ball, in Two Player Mode getting the ball past the other player’s paddle increases the score up to the chosen maximum. If the ball is to be served on the next loop because a player missed a bounce then then a variable called gameState is set to indicate that a serve is needed and towards which player the serve will go. If the gameState variable is left untouched then the game continues as normal by updating the paddle position, ball position and then drawing it on the LCD. If the button is pushed or one of the ending conditions is met the game loop ends and the player(s) are returned to the splash screen by the main loop of the program.

The majority of the program is handled using simple math, loops and if statements but interfacing with the LCD was a big challenge for me. The LCD takes information as 8bits on 8 DB pins as well as a Register Selection pin which determines of the 8bits of data is a command or data to be written to the LCD’s memory, finally there is an enable pin which is toggled to indicate to the LCD that the current input values are valid. In order to quickly set the values of the 8 DB pins I had to learn about Bit Masking, this is where you perform a logical AND function on your data byte and a mask. For example, if I want to know the state of the x bit in this byte 0000x000 I can perform a logical AND between it and 0000100. Because all of the undesired bits in the bitmask 00001000 are zero they will always result in a zero, the value of x will however be in the result because x AND 1 = x. By using a different bit mask to check each bit of the byte I want to send I could determine which DB pins should be on and which should be off.

Where B is the byte of data I want to send then the value of each DB pin could be determined in the following way. When turning an output pin on or off in Arm Basic applying any non-zero value will turn the pin on so it doesn’t matter that the pin I use for DB7 will be told “OUT(DB 7 pin) = 10000000,” the pin will always be on when that bit is on.

DB7 = B AND %10000000
DB6 = B AND %01000000
DB5 = B AND 100000
DB4 = B AND 010000
DB3 = B AND 001000
DB2 = B AND 000100
DB1 = B AND 000010
DB0 = B AND 000001

The other big hurtle was to take the xy data of the ball and paddle positions and translate them into something that was compatible with how the LCD works. Being an alphanumeric display it is only made to show characters from it’s ROM and 8 custom characters that can be programmed by the user. These 8 custom characters are 5 pixels wide and 8 pixels tall, by arranging them in a 4 wide by 2 tall grid it is possible to create a 20x16 pixel graphical display with room for score keeping (and debugging) on either side.

Each row of a character has an address (the CGRAM address) and shows the state of the 5 lowest bits of the byte stored at that address. So my 20x16 area is split up into 64 addresses with each address containing 5 pixels each.

By mapping out the locations of the addresses I was able to make a pair of functions that would return the CGRAM address and the value of the byte that should be stored in that address for any given x and y pixel position, I could then write this byte to the appropriate CGRAM address and display the playing field.

For a more detailed explanation of the functions I used you can check out a video I did on the subject linked here: Bit Mapping on the 1602a.

Finally after about a month of development and testing I was ready to box up my portable Pong project in a suitably retro looking enclosure and call it complete.

Monday, August 28, 2017

Persistent LiveUSB Debian 9 Stretch

Live CD and USB operating systems are a great tool for working on computers with a slow or broken OS, they let you bring all your tools with you and don't need to make any changes to the host PC in order to operate. There are a number of Linux LiveCD distributions that are built for general use or specific tasks like file recover or drive partitioning but most of them lack "persistence." When you boot up a live CD/USB it is always the first boot, changes you made the last time you ran it do not carry over to the next.

Although there being a few live distributions that do have persistence, Debian, which I am most familiar with, is not one of them. After some moderate Googling I found a tutorial here: Creating a Debian Live Iso-Hybrid USB key with persistence which shows how to take the non-persistent Debian Live ISO and give it the ability to save any changes you make.

The process involves making 2 partitions on a USB stick, one to hold the operating system and one to hold any changes you make when you run the OS. The Debian Live ISO is extracted into the first partition and a few changes are made. Note in step 4 there is no longer a /syslinux/live.cfg and the word "persistence" was added to live boot option in /syslinux/menu.cfg instead. After booting the USB stick for the first time I also found it necessary to change the repository URLs in /etc/apt/sources.list to my local mirror in order to install new software.

With those two deviations from the original tutorial I was able to get a full system that can have software added and files stored and will run on nearly any PC.

Thursday, August 24, 2017

Fast growing Ice Crystals

Dry ice is a great material to have in a shop that can be a workable stand in for liquid nitrogen in most cases. When left unattended for a couple minutes water in the air will freeze on the dry ice's surface and form a furry coating. After the dry ice has completely sublimated the water ice begins to warm up to room temperature and melts a few seconds later. Normally the water ice crystals are so small that they appear to be a uniform fur but putting a small grain of dry ice under the microscope shows how complex the growing crystals really are.

Tuesday, April 4, 2017

Caching a "Bullet"

In my quest to get a ping pong ball up to speeds normally only achieved by military aircraft and light arms I ran into a metering problem. With my 1200 frame per second camera the ball only appeared in frame for 1 to 3 frames depending on how lucky I was. By having a length reference and knowing how long the shutter was open it was sometimes possible to calculate how fast the ball was moving by measuring how long its "streak" appeared to be in an image. This was only somewhat accurate and relied on the chance that the streak both started and ended in frame during one exposure so I came up with a much more accurate (and cheap) measurement apparatus.

I put two strips of aluminum foil 30cm apart and held tightly in a frame, using some alligator clips and 3.5mm stereo jacks I fed the output of my audio card into one end of each strip. On the other end I used more gator clips to feed the signal (from the audio card, and through the foil) back into the input of the audio card. When the ball is fired through the two strips they break a couple fractions of a second apart, by playing a tone through the strips and recording the result it is possible to count the number of audio samples (at 48,000samples per second) between the breaks. Now I have both an accurate measurement of the distance traveled and an accurate measurement of the time it took, letting me measure the speed of my ping pong balls with much more precision than my 1200fps camera.

Sunday, January 8, 2017

Paul Particle Trap

Normally a Paul Trap is used to catch individual ions, single nuclei or charged molecules, and then sort them according to their m/z ratio (mass to charge). However it is possible to scale the whole idea up to a table top size in order to catch finely ground powders like flour or corn starch.

The trap works by alternately pulling and pushing the particles in 2 or 3 axis. For one half of the cycle they are pulled up and down while being pushed inward from the sides, when the polarity of the trap reverses the forces reverse as well. The particles move according to the forces they feel but never get far before the reversal, trapping them in a small volume of space. When the voltage on the trap is increased the particles with the most charge relative to their mass will pick up more speed and eventually be flung from the trap, when the voltage is decreased the particles with the most mass relative to their charge will be overcome by gravity and will fall from the trap, in this way ions are sorted for used in mass spectrometers.

Thursday, December 8, 2016

Homemade Strain Gauge

I work with a lot of electronic scales, weighing raw materials, trucks and finished product, every one of those scales contains one or more load cells. Up until a few weeks ago, load cells were a mysterious aluminum block that turned static load into a weight on a scale. After a couple hours of Google-Fu I found that the important part of every load cell was a strain gauge, a variable resistor that changed value as it is deformed.

Strain gauges are generally described as a conductor that will be stretched along with a substrate, causing the conductor to become thinner and more resistive. When the substrate is squeezed the conductors are bunched up and become thicker, decreasing the resistance, it sounds simple enough until I figured out how little the resistance actually changes. Using about 250cm of very fine wire I was only able to measure a change of about 8mOhms. Normally 8mOhms would not be a huge problem for measurement but the total resistance of the strain gauge was 50.008 ohms.

To think of it another way, imagine measuring a 50meter long bar and trying to find out if it has grown or shrunk by 8mm BUT the tool you use has to measure the entire length, there aren't many tools that do that kind of accuracy for cheap. Instead of trying to measure the whole value I used a wheatstone bridge to measure only the change in resistance, this is like laying out a known 50meter bar next to the one you want to measure and then checking the difference between the two, this is much easier and can be done with non-specialized tools in both the physical and electrical examples.

Thursday, October 20, 2016

Electrically Conductive Flame

Reading about high voltage it is often mentioned that flames contain plasma, like an electrical arc, and are electrically conductive. A candle placed between the leads of a high voltage transformer will draw the arc longer, its flame will also wick away the charge on my Van De Graaff when brought near. But, when I try to pass 120v current through or measure the resistance of the flame with a meter it seems to be an open circuit

After doing some more reading I found most candle flames aren't hot enough to be conductive. In order to make the charge carriers (electrons) mobile enough to conduct current, the flame has to be hot enough to give the electrons the energy needed to break free from their atoms. With some experimenting I found that some metals work well and others will not, when exposed to flame copper forms a skin of copper oxide which will insulated it from the flame quite a bit, clean steel seemed to work a lot better. A little more tinkering showed that geometry is important as well, getting the most metal possible in contact with the flame increased the conductivity to the point where a very weak audio signal could be passed, and I could make this video.

With a pair of large parallel plates, and a very hot flame it could even be possible to generate current using a magnetohydrodynamic generator! Putting strong magnets perpendicular to the plates and the flow of the flame would cause the charges in the flame to migrate to one plate or the other, resulting in a measurable voltage.