Posted on

X/Y Laser pointer controller

PIC Output
A long time ago I decided to build a controller that would direct a laser pointer, The idea was to have 2 speakers connected to mirrors so they deflect in the x/y range. This allows the laser to be aimed around at will.

A simple Pic 16f84 was the controller with an analog devices Dual DAC. The dac has a lock on the output so both x and y get updated at the same time. The pic simply loads an 8bit data value for x, then y, then updates the DAC output.

I originaly had some nice Mirror galvanometers from an old laserdisk player to aim the beam, these were a lot better than speakers, however they are not easily accessable for most people. The output of the DAC was centered at 2.5v with a 2.5v swing each way from the 5v supply. This gives a nice AC output from -2.5v to 2.5v relative to the output ‘gnd’ Great for connecting into cheap audio amps for driving the mirror speakers.

The hard part is firmware on the pic. My original plan was to make writing, but this is quite a complex task. I managed to get a box, a circle, triangle etc but am still working on drawing complex shapes. A third Z axis was provided in the form of a digital out from the pic to turn the laser on/off. This allows seperation of drawn objects.

I have a couple of games planned, first is pong, the 3 shapes needed here are simple and should be easy to draw. Then asteroids. A lot more complex.

The final game should be a small handheld box that projects a laser ‘vector’ game onto any surface. Obviously the power of the laser changes how visible the game is under different conditions.

Component Side Copper Side PIC Output Square
This was the first PCB I ever made, it was printed by laser printer onto tranparency, UV exposed onto pre-etch resist coated board and acid etched.

Here is the initial CC5X code, its pretty basic though,

#pragma chip PIC16C84
#pragma config WDTE=off, FOSC=XT, PWRTE=on

// #pragma config &= 0x3FF9

#include “delay.c”

/* IO-CONFIGURATION: */
#define Konfig_portA 0x08 /* xxxx 1000, 1=INPUT */
#define Init_portA 0x00 /* 0000 0000 bits 1,2 are dac control, 4 is laser and 8 is input*/

#define Konfig_portB 0x00 /* 0000 0000, 0=Output */
#define Init_portB 0x00 /* 0000 0000 All 8 bits output to send data to Dacs*/
#define UPDATE 0x00 /* LDAC and DACAB are inverted */
#define FREEZE 0x01 /* So 0 in update makes the DAC update */
#define DACX 0x00 /* and 1 makes it freeze its current data */
#define DACY 0x01 /* Just some friendly names for the dacs */

#pragma bit LDAC @ PORTA.0
#pragma bit DACAB @ PORTA.1
#pragma bit LASER @ PORTA.2
#pragma bit INPIN @ PORTA.3

#pragma bit PIN1 @ PORTB.0
#pragma bit PIN2 @ PORTB.1
#pragma bit PIN3 @ PORTB.2
#pragma bit PIN4 @ PORTB.3
#pragma bit PIN5 @ PORTB.4
#pragma bit PIN6 @ PORTB.5
#pragma bit PIN7 @ PORTB.6
#pragma bit PIN8 @ PORTB.7

void main ( void)
{
unsigned x,y,t;
/* initialize */
PORTA = Init_portA;
TRISA = Konfig_portA;
PORTB = Init_portB;
TRISB = Konfig_portB;

x=0;
y=0;

DACAB = DACX;
LDAC = FREEZE;

while (1)
{
DACAB = DACX; /* The dac seems to work a lot faster than the PIC so no delay is needed */
PORTB = x; /* but that is based on ititial slow work observations */
DACAB = DACY; /* Although Both dacs appear to change independantly ok with this */
PORTB = y; /* even though there is no delay */
LDAC = UPDATE; /* The rest of the program provides a delay while dacs settle! */
LDAC = FREEZE; /* The dacs update now, while the prog does its work */

if (x==255) y–; /* If at right, go down */
if (y==255) x++; /* if at bottom go left */
if (x==0) y++; /* If at left, go up */
if (y==0) x–; /* if at top, go right */
/* delay(2); */
}
}