X-Y Plotter Table For The TI 99/4A Computer - Final
So I've been mulling the idea of creating an X-Y table for my TI computer, which could be used to draw a bitmap image or perhaps do some laser engraving. I searched the web for inspiration and found this ingenious video by HomoFaciens where he uses the stepper platform that moves the laser head in optical drives to create a very effective but small X-Y plotter.
https://youtu.be/-XhMT4wXSG4
So I went ahead an found a couple of used DVD-ROM drives on Ebay and ripped them apart, only to find that only one of them had a stepper motor assembly. According to HomoFaciens, only about 50% of the optical drives actually use stepper motors. Nonetheless, I figured I could start by experimenting in controlling the stepper platform with the TI's parallel (PIO) port. Below is the actual stepper motor assembly from one of the drives:
The stepper motor in this assembly is a 4 wire stepper motor, which means it has 2 coils with each pair of wires going to one coil. It's easy to identify each pair by simply doing a continuity test on the wires using a multimeter. To move the motor in one direction, one of the coil has to cycle it's polarity repeatedly between positive and negative while the other coil is idle. To reverse the motion, simply repeat the process using the second coil.
In order to be able to control the polarity on the coil, one could use relay circuits like the one on my robotic arm controller, or more commonly use an H-bridge circuit as below:
Based on the input to the 4 input points on the circuit marked A, B, C and D, the polarity can be switched at will. The table below shows how to do this.
Given that we have 2 coils in the stepper motor, we obviously will need 2 H-bridges to control it, one for each coil. While you can purchase ready made stepper motor controllers on most hobbyist sites, it's really pretty simple to build for just pennies, so I went ahead and breadboarded a couple of H-bridges for test purposes.
As for the connection to the TI, I decided to allocate one data pin on the PIO port to each input port on the H-bridges, which means that all the data pins will be used (Eight). This is problematic because the X-Y table will need 2 stepper motors at a minimum, one for the X axis and one for the Y axis, and I obviously will not have enough data pins for that. The solution is going to involve some kind of multiplexing, but we'll come back to that. For now let's make sure this thing actually works!
Here's the connection layout:
Coil 1:
A --> D7
B --> D6
C --> D5
D --> D4
Coil 2:
A --> D3
B --> D2
C --> D1
D --> D0
So in order to control the coils, I just need to send the appropriate byte pattern to the PIO port. For example, in order to run the stepper motor forward, coil 1 needs to have a bit pattern of 1100 corresponding to the DCAB H-bridge inputs, and coil 2 needs to be inactive, which translates to a bit pattern of 1010 (refer to the table above). Putting it all together we get:
Coil 2 Coil 1D C B A D C B AD0 D1 D2 D3 D4 D5 D6 D71 0 1 0 1 1 0 0
Converting this 8-bit binary number to decimal we get 172, which we can send to the PIO port via the CALL LOAD command in Rich Extended Basic. Then we reverse the polarity of coil 1 while keeping coil 2 inactive to keep the stepper motor moving forward and so on and so forth.
Here's the control program on the TI. I opted to use Rich Extended Basic for its ease of use and unique ability to allow low-level access to hardware. Below is the test program listing:
10 CALL CLEAR20 CRU=2432 ! RS232 CARD CRU ADDRESS IS >1300 (4864). RXB USES CRU/230 CALL IO(3,1,CRU,1) ! ACTIVATE THE RS232 CARD40 CALL IO(3,1,CRU+7,1) ! TURN ON THE LED ON THE CARD50 CALL IO(3,1,CRU+1,0) ! SET THE PIO PORT TO OUTPUT60 FOR I=1 TO 30 ! 30 FORWARD STEPS70 CALL LOAD(20480,172) ! COIL 1 POSITIVE POLARITY - COIL 2 INACTIVE -- PIO ADDRESS IS 2048080 GOSUB 500 ! DELAY TO SLOW DOWN THE MOVEMENT90 CALL LOAD(20480,163) ! COIL 1 NEGATIVE POLARITY - COIL 2 INACTIVE100 GOSUB 500110 NEXT I 120 FOR I=1 TO 30 ! 30 REVERSE STEPS130 CALL LOAD(20480,202) ! COIL 1 INACTIVE - COIL 2 POSITIVE POLARITY140 GOSUB 500150 CALL LOAD(20480,58) ! COIL 1 INACTIVE - COIL 2 NEGATIVE POLARITY160 GOSUB 500170 NEXT I180 GOTO 60 ! REPEAT THE ENTIRE PROCESS500 FOR D=1 TO 200::NEXT D::RETURN
And here's what it looks like in action:
https://youtu.be/lATGB60ut0w
So while it works in principle, as I mentioned in the video there are several issues to contend with if we are to use the DVD-ROM assemblies:
- The quality of the worm gear assembly is highly variable. Mine was pretty bad...
- The weight that could be supported by the carrier is tiny on my drive assembly, so it will not be able to hold a second assembly on top for the Y axis.
- The usable draw area is very small, 40x40 steps on my drive assembly, so not very practical.
I don't know how many optical drives HomoFaciens had to go through before he got the high quality ones he demonstrated, but I'm not terribly inclined to go that route. This of course means that I will have to build my own table.
UPDATE 6/10/18
Pack007 suggested using a 74HC595 8-bit serial shift register chip for multiplexing to PIO data lines, and it worked extremely well. That chip basically takes in an 8 bit number serially one bit at a time starting with the LSB and outputs that number in parallel using 8 output lines. In addition it has an Output Enable pin which places the parallel output pins in a high impedance state when high, effectively inactivating the chip. The control sequence will go like this:
- Make the LATCH pin (12) low to isolate the serial input from the output
- Activate the chip by making the OE pin (13) low
- Present 1 bit to the DATA pin (14) and cycle the CLOCK pin (11)
- Go back to 3 until all 8 bits are in
- Cycle the LATCH pin (12) to present the number to the output pins
- Go back to 1 for the next number
The output 8-bit number will be coded per the coil sequence discussed earlier and connected to the H-bridges accordingly for the stepper motor. Here's the circuit diagram for a single motor:
PIO Connections:D7 (2) --> DATAD6 (3) --> OE for motor 1D5 (4) --> OE for motor 2D4 (5) --> OE for motor 3HSKOUT (1) --> CLOCKSPROUT (14) --> LATCH
Now we will need 3 stepper motors for the plotter: X, Y and Pen. The way this will work is that each motor will have 2 H-bridges connected to a separate 74HC595 chip. These 3 chips will share the LATCH, CLOCK and DATA pins connections but will each have their own OE pin connections. That way, the computer will be able to select the desired motor by simply making the corresponding OE line low and the other 2 OE lines high. All in all, only 6 output lines from the PIO port will be needed instead of the 24 lines required without multiplexing. Problem solved! This leaves me with several lines that could be used to detect axis end of travel through the use of micro-switches.
And here's the RXB test code. It's definitely a slower process than the previous direct parallel method, but it's the price to pay for multiplexing. This is fine for testing, but I might have to switch to assembly for the final control program in order to speed things up. We'll see...
10 CALL CLEAR11 OE1=12 ! BIT PATTERN TO ISOLATE MOTOR 114 DIM FWD(16),REV(16),OFF(15 CRU=2432 ! CRU BASE OF RS232 CARD DIVIDED BY 220 CALL IO(3,1,CRU,1) ! ACTIVATE RS232 CARD30 CALL IO(3,1 CRU+7,1) ! TURN LED ON40 CALL IO(3,1,CRU+1,0) ! SET PIO TO OUTPUT50 FOR I=0 TO 15::READ FWD(I)::NEXT I ! READ FORWARD CONTROL SEQUENCE60 FOR I=0 TO 15::READ REV(I)::NEXT I ! READ REVERSE CONTROL SEQUENCE70 FOR I=0 TO 8::READ OFF(I)::NEXT I ! READ IDLE CONTROL SEQUENCE80 REM MOTOR 1 MOVE FORWARD90 CALL IO(3,1,CRU+3,0) ! MAKE LATCH PIN LOW100 CALL LOAD(20480,OE1) ! ISOLATE MOTOR 1110 FOR I=1 TO 30 ! 30 FORWARD STEPS120 FOR N=0 TO 15 ! FORWARD BIT SEQUENCE IS 2 8-BIT NUMBERS LONG (16 BITS)121 REM THE LINE BELOW SENDS A SINGLE BIT OUT THE PIO LSB (D7) PIN 122 REM IF THE BIT IS 1, IT IS ADDED TO THE OE1 BIT PATTERN (D6-D4)123 REM OTHERWISE ONLY OE1 IS SENT AND D7 REMAINS 0130 IF FWD(N)=1 THEN CALL LOAD(20480,OE1+1) ELSE CALL LOAD(20480,OE1) 140 CALL IO(3,1,CRU+2,1)::CALL IO(3,1,CRU+2,0) ! CYCLE THE CLOCK PIN141 REM THE LINE BELOW PRESENTS THE 8-BIT NUMBER TO OUTPUT150 IF N=7 OR N=15 THEN CALL IO(3,1,CRU+3,1)::CALL IO(3,1,CRU+3,0) ! CYCLE THE LATCH PIN160 NEXT N170 NEXT I 180 REM MOTOR 1 REVERSE MOVE190 FOR I=1 TO 30 ! 30 REVERSE STEPS200 FOR N=0 TO 15 ! REVERSE BIT SEQUENCE IS 2 8-BIT NUMBERS LONG (16 BITS)201 REM THE LINE BELOW SENDS A SINGLE BIT OUT THE PIO LSB (D7) PIN 202 REM IF THE BIT IS 1, IT IS ADDED TO THE OE1 BIT PATTERN (D6-D4)203 REM OTHERWISE ONLY OE1 IS SENT AND D7 REMAINS 0210 IF REV(N)=1 THEN CALL LOAD(20480,OE1+1) ELSE CALL LOAD(20480,OE1) 220 CALL IO(3,1,CRU+2,1)::CALL IO(3,1,CRU+2,0) ! CYCLE THE CLOCK PIN221 REM THE LINE BELOW PRESENTS THE 8-BIT NUMBER TO OUTPUT230 IF N=7 OR N=15 THEN CALL IO(3,1,CRU+3,1)::CALL IO(3,1,CRU+3,0) ! CYCLE THE LATCH PIN240 NEXT N250 NEXT I260 GOTO 110 ! REPEAT THE PROCESS500 REM MOTOR ACTIVATION SEQUENCES510 REM FORWARD520 DATA 0,0,1,1,0,1,0,1,1,1,0,0,0,1,0,1530 REM REVERSE540 DATA 0,1,0,1,0,0,1,1,0,1,0,1,1,1,0,0550 REM IDLE560 DATA 0,1,0,1,0,1,0,1
It is likely I will need to use more beefy transistors for the H-bridges because the current needed by the stepper motors in the final design will be hefty. However, the basic circuit design will remain the same.
Next I'm going to focus on the mechanical assembly.
Update 6/14/18
Soooo, to be perfectly honest I have not been too happy with the performance of the stepper motor extracted from the optical drive. The torque was way too low and the steps were far too large and I had the nagging suspicion I was doing something wrong, and indeed I was!
After further research, it turned out that my step control sequence was incomplete, and I was essentially skipping every other step. The correct sequence for a bipolar 4-wire stepper motor like the one I have turned to be as below:
A and B represent the 2 coils in the motor. To reverse the rotation, simply swap the sequences of A and B. And sure enough when I applied that sequence the torque increased dramatically because both coils were always energized at any one time and the steps were much smaller and smoother. Live and learn
Furthermore, after taking a closer look at the H-bridge circuit I had used and comparing it to other circuits out there, I realized that there was no need to use a mix of NPN and PNP transistors, and that just NPN ones will do the trick, as well as only require 2 input pins for control instead of 4 per H-bridge! And that meant that now I could control 2 stepper motors using only one 74HC595 chip instead of 2 chips! Here's the updated circuit for a single motor:
The new PIO connections become:
PIO Connections:D7 (2) --> DATAD6 (3) --> OE for motor 1 & 2D5 (4) --> OE for motor 3HSKOUT (1) --> CLOCKSPROUT (14) --> LATCH
And the control sequence for the steps will be as below, with A and B this time representing each H-bridge input:
COIL 2 COIL 1 A B A B ---------------------- 1 0 1 0 FORWARD 0 1 1 0 0 1 0 1 1 0 0 1 1 0 1 0 REVERSE 1 0 0 1 0 1 0 1 0 1 1 0
Amended RXB control test program. Notice that the trailing 4 zero bits of each byte in the control sequences are reserved for the future control of the seconds stepper motor.
10 CALL CLEAR20 OE1=4 ! ISOLATE MOTORS 1 & 230 OE2=2 ! ISOLATE MOTOR 340 DIM FWD(32),REV(32)50 CRU=2432 ! BASE RS232 / 260 CALL IO(3,1,CRU,1) ! ACTIVATE RS232 CARD70 CALL IO(3,1,CRU+7,1) ! TURN LED ON80 CALL IO(3,1,CRU+1,0) ! SET PIO TO OUTPUT90 FOR I=1 TO 31::READ FWD(I)::NEXT I100 FOR I=1 TO 31::READ REV(I)::NEXT I110 REM FORWARD STEPS120 CALL IO(3,1,CRU+3,1) ! MAKE LATCH LOW130 CALL LOAD(20480,OE1) ! ISOLATE MOTORS 1 & 2140 FOR I=1 TO 5 150 FOR N=0 TO 31155 REM LINE BELOW SENDS DATA BIT BY BIT VIA D7 PIN ON PIO PORT160 IF FWD(I)=1 THEN CALL LOAD(20480,OE1+1) ELSE CALL LOAD(20480,OE1)170 CALL IO(3,1,CRU+2,1)::CALL IO(3,1,CRU+2,0) ! PULSE CLOCK180 IF N=7 OR N=15 OR N=23 OR N=31 THEN CALL IO(3,1,CRU+3,1)::CALL IO(3,1,CRU+3,0) ! CYCLE LATCH190 NEXT N200 NEXT I210 REM REVERSE STEPS220 FOR I=1 TO 5230 FOR N=0 TO 31240 IF REV(N)=1 THEN CALL LOAD(20480,OE1+1) ELSE CALL LOAD(20480,OE1)250 CALL IO(3,1,CRU+2,1)::CALL IO(3,1,CRU+2,0) ! PULSE CLOCK260 IF N=7 OR N=15 OR N=23 OR N=31 THEN CALL IO(3,1,CRU+3,1)::CALL IO(3,1,CRU+3,0) ! CYCLE LATCH270 NEXT N280 NEXT I290 GOTO 140500 REM MOTOR ACTIVATION SEQUENCES510 REM FORWARD520 DATA 1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,1,0,0,0,0530 REM BACKWARD540 DATA 1,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,1,0,0,0,0,0
And here's the whole thing in action:
https://youtu.be/_uG1AQPhN_s
OK now I can focus on the mechanical assembly
Update 6/17/18
Quick update here: I re-wrote the stepper motor control program in assembly (quick and dirty draft) and the speed difference was remarkable as seen in the video below. I actually could drive the motor much faster than this, but it would likely damage it... And here's where the usefulness of RXB really comes through: it's super efficient to use for rapid prototyping and validation of design ideas because of the ease of editing and running, and once everything is working properly then porting to assembly, if needed for speed, can be done in a fairly straightforward manner.
https://youtu.be/GryJ9L2fv1g
Update 6/30/18
The mechanical assembly of the X-Y Plotter is now completed. I eventually settled down on an overlapping table design because I felt it would be a bit more compact.
I started by getting my hands on a couple of cheap rod sets on Amazon along with 2 of the ubiquitous Nema 17 4-wire bipolar stepper motors.
Unfortunately, I suppose you get what you pay for, and the rod sets were not well matched at all, with the threaded rod supports being shorter than the sliding rod ones, and thus required a bunch of risers in order to even things out. Furthermore, the threaded rods came with an odd circular nut rather than a flat sided one, making the attachment of a platform to the nut much more of a pain than it had to be. Essentially I had to carve out slots under each platform into which the nut was inserted and glued. The platforms were cut from 5mm thick birch plywood which is pretty stiff.
One issue I noted was that the second level platform tended to sag a little bit when the pen holder platform was all the way to the end, and the whole assembly tended to tip as well. The solution was a simple free coasting wheel on the edge of the second platform for support. For the pen up/down function, I chose to use the stepper motor assembly I had pulled out from the old DVD-ROM drive which I have shown earlier since little torque was going to be needed for that function. I created a simple pen bracket with a set screw which I glued to the lens assembly along with a couple of support brackets.
Time to put the 3D printer to good use!
And here's the final product.
Finally I added limit switches to the X and Y axes as well as the pen control assembly so that I could initialize the plotter to the origin before each print.
Overall I'm pretty happy with the end result. Next step is finalizing the control circuitry for the Nema 17 motors. These draw a lot of current and cannot be driven by the test circuit I demonstrated earlier.
Update 8/1/18
I did some testing to figure out how to properly power and control the Nema 17 stepper motors as seen below. Several components' leads did not fit in the breadboard holes, so I ended up with a huge wire mess... The good news is that is miraculously worked! I opted to reduce the component count by using the L298 H-bridge controller, one for each of the stepper motors.
From there, I designed a complete control circuit schematic and a double-sided PCB layout. It's not a professional design, but it's the best I could do with my limited skill set:
The 4 pads at the corners are needed for later alignment.
Next is the actual PCB build...
Update 8/2/18
Printed the layout on transparency sheets using my laser printer. Two copies per PCB side in order to maximize the tracings opacity.
Exposure of a double-sided pre-sensitized PCB for 8 minutes under a fluorescent light. I cannot stress enough the need to use a high quality PCB here. I have had very good luck with MG Chemicals. The cheap Chinese stuff is terrible as I painfully discovered from past experience. Aligning the top and bottom layers was fussy work. I marked and drilled into the PCB the 4 corner pads and used pins to go through the top transparency, the PCB itself, and the bottom transparency and I got near-perfect alignment that way. Only 2 pins were really needed.
And here's the exposed and developed PCB
Next I etched the board, and I have to say it turned out overall pretty nice. It is super important at this point to test each trace for continuity and bridges as well for the possibility of a short. I found 3 trace breaks and couple of bridges that way. It is so much easier to fix the issues at this stage rather than try to debug the board once it is fully populated.
Finally I drilled the pads. i start with a very small drill bit and test fit all the components, drilling progressively larger holes as needed. Again this needs to be done before you do any soldering for component!
This was probably the largest double-sided PCB I have ever built! In case you are wondering whether it was worth the effort, it's really more of a philosophy than an economic question. I personally enjoy the challenge of designing and building my projects from scratch as much as possible, although I would definitely get far more professional results had I farmed them out to a PCB fabrication house and it would likely have been cheaper too...
I'm going to defer the actual soldering and final testing until I get back from vacation at the end of the month. I need a break anyway
Update 10/6/18
I have been quite busy behind the scenes over the past month getting this contraption to work, and I think I finally got it.
The board assembly went without too much difficulty and actually looks overall pretty good for a homemade amateur job although bridging the top and bottom traces was fastidious since obviously the holes are not plated through and through.
After completing the trace bridging
Assembled board. The large heat sinks are for the L298 H-bridges which can run very hot.
Now no prototype design ever survives it's first iteration, and this was no exception. Of course when first powered up nothing worked (surprise! ). It took me an entire week of extensive testing to figure out all the issues. First, I had forgotten to bridge one of the vias on the board, and there were a few tiny solder bridges as well. Then I found out that I had made a mistake by assigning the PIO pin 11 (ground) as Vss instead of pin 12, so ended up frying both of the 74HC595 chips... And lastly I had neglected to tie the PIO handshake in line to Vss via a pull-up resistor, and thus the end of travel switches did not work. Overall not too bad actually, as the general design was relatively sound...
Debugging in process...
Below are the updated schematics and PCB layouts:
Bottom layer and top component outline
Top layer
But even when I got the controller board finally working, I was not happy with the motions of the stepper motors and they were running very rough. After some more research it turned out that my step sequence for the stepper motors was wrong when running in reverse. You see, there is lots of documentation online on the forward step sequence of bipolar stepper motors, but not a single mention of how to run them in reverse. I finally reverted to looking at the source of the Arduino stepper library and it turned out that all one needed to do was simply run the sequence in the opposite order starting with the last position in the sequence. Doh... Once I fixed that, the motors ran great.
But then another issue surfaced where the stepper motor I was using for the pen up/down function would not run well when supplied with more than 5V, and this voltage was barely enough to run the Nema 17 stepper motors for the X and Y axes. It took me a while to realize that the problem was with the voltage, and I was very close to trashing the pen assembly thinking that the pen stepper motor was damaged. Note to self: always try to match the stepper motors in a project to minimize headaches and preserve hair... In any case, I am now at a point where everything is working as it should and the next step is going to be actually getting the device to draw something. That's coming next.
Assembly language plotter control program:
* 2D PLOTTER CONTROL PROGRAM ** OCTOBER 2018 * DEF STARTGPLSTS EQU >8375 GPL STATUS BYTEPIO EQU >5000 PIO PORT ADDRESSDATLOC BSS 2 MOTOR SEQUENCES DATA LOCATIONDATORG BSS 2 START OF MOTOR SEQUENCESSUBRTN BSS 2 SUBROUTINE RETURN ADDRESSSUBRT1 BSS 2 SUBROUTINE RETURN ADDRESSSUBRT2 BSS 2 SUBROUTINE RETURN ADDRESSSUBRT3 BSS 2 SUBROUTINE RETURN ADDRESSSUBRT4 BSS 2 SUBROUTINE RETURN ADDRESSSEL DATA >0400 >0400=X OR Y, >0200=PENXPTR DATA 0 STEP POINTER FOR X MOTORYPTR DATA 0 STEP POINTER FOR Y MOTORPPTR DATA 0 STEP POINTER FOR PEN MOTORDELVAL DATA 50 DELAY COUNTER VALUE * MOTOR ACTIVATION SEQUENCES* X AND PEN MOTORSXPMDAT BYTE >01,>00,>01,>00,>00,>00,>00,>00 BYTE >00,>01,>01,>00,>00,>00,>00,>00 BYTE >00,>01,>00,>01,>00,>00,>00,>00 BYTE >01,>00,>00,>01,>00,>00,>00,>00 * Y MOTORYMDAT BYTE >00,>00,>00,>00,>01,>00,>01,>00 BYTE >00,>00,>00,>00,>00,>01,>01,>00 BYTE >00,>00,>00,>00,>00,>01,>00,>01 BYTE >00,>00,>00,>00,>01,>00,>00,>01 * INITIALIZE THE PIO PORTSTART LI R12,>1300 SELECT CRU ADDRESS OF RS232 CARD SBO 0 ACTIVATE CARD SBO 7 TURN CARD LED ON CLR @PIO CLEAR PIO PORT SBZ 1 SET PIO TO OUTPUT * DEMO BL @INITX LI R5,400 BL @FWD MOV R2,@XPTR BL @INITX LI R5,400 BL @REV MOV R2,@XPTR BL @INITY LI R5,400 BL @FWD MOV R2,@YPTR BL @INITY LI R5,400 BL @REV MOV R2,@YPTR BL @INITP LI R5,70 BL @FWD MOV R2,@PPTR BL @INITP LI R5,70 BL @REV MOV R2,@PPTR BL @HOME B @SHTDN ********************************************************************************* HOME MOTORS ROUTINEHOME MOV R11,@SUBRT4 BL @INITX INITIALIZE X MOTORREDOX TB 2 CHECK IF END OF TRAVEL SWITCH TRIGGERED JNE DONEX IF YES MOVE X MOTOR RIGHT LI R5,1 NUMBER OF STEPS BL @REV MOVE X MOTOR TO LEFT 1 STEP JMP REDOXDONEX MOV R2,@XPTR BL @INITX LI R5,60 NUMBER OF STEPS BL @FWD MOVE X MOTOR 60 STEPS TO RIGHT MOV R2,@XPTR SAVE CURRENT SEQUENCE POINTER BL @INITY INITIALIZE Y MOTORREDOY TB 2 CHECK IF END OF TRAVEL SWITCH TRIGGERED JNE DONEY IF YES MOVE Y MOTOR UP LI R5,1 NUMBER OF STEPS BL @REV MOV Y MOTOR DOWN 1 STEP JMP REDOYDONEY MOV R2,@YPTR BL @INITY LI R5,80 NUMBER OF STEPS BL @FWD MOVE Y MOTOR 80 STEPS UP MOV R2,@YPTR SAVE CURRENT SEQUENCE POINTER BL @INITP INITIALIZE PEN MOTORREDOP TB 2 CHECK IF END OF TRAVEL SWITCH TRIGGERED JNE DONEP IF YES MOVE PEN MOTOR UP LI R5,1 NUMBER OF STEPS BL @REV MOV PEN MOTOR 1 STEP DOWN JMP REDOPDONEP MOV R2,@PPTR BL @INITP LI R5,25 NUMBER OF STEPS BL @FWD MOVE PEN MOTOR UP 25 STEPS MOV R2,@PPTR SAVE CURRENT SEQUENCE POINTER MOV @SUBRT4,R11 B *R11******************************************************************************** ********************************************************************************* INITIALIZE X MOTOR ROUTINEINITX MOV R11,@SUBRT3 LI R1,XPMDAT MOV R1,@DATORG MOV @XPTR,R2 SLA R2,3 A R2,R1 MOV R1,@DATLOC LI R1,>0400 SELECT X/Y CHIP MOV R1,@SEL LI R7,75 SET DELAY MOV R7,@DELVAL MOV @XPTR,R2 MOV @SUBRT3,R11 B *R11******************************************************************************** ********************************************************************************* INITIALIZE Y MOTOR ROUTINEINITY MOV R11,@SUBRT3 LI R1,YMDAT MOV R1,@DATORG MOV @YPTR,R2 SLA R2,3 A R2,R1 MOV R1,@DATLOC LI R1,>0400 MOV R1,@SEL LI R7,75 MOV R7,@DELVAL MOV @YPTR,R2 MOV @SUBRT3,R11 B *R11******************************************************************************** ********************************************************************************* INITIALIZE PEN MOTORINITP MOV R11,@SUBRT3 LI R1,XPMDAT MOV R1,@DATORG MOV @PPTR,R2 SLA R2,3 A R2,R1 MOV R1,@DATLOC LI R1,>0200 MOV R1,@SEL LI R7,400 MOV R7,@DELVAL MOV @PPTR,R2 MOV @SUBRT3,R11 B *R11******************************************************************************** ********************************************************************************* MOVE MOTOR FORWARDFWD MOV R11,@SUBRT2 LI R4,1 FORWARD DIRECTION BL @MTRDRV MOV @SUBRT2,R11 B *R11******************************************************************************** ********************************************************************************* MOVE MOTOR IN REVERSEREV MOV R11,@SUBRT2 LI R4,-1 REVERSE DIRECTION BL @MTRDRV MOV @SUBRT2,R11 B *R11******************************************************************************** ********************************************************************************* MOVE MOTOR ROUTINE* R4 = DIRECTION (1/-1), R5 = NUMBER OF STEPS* R2 = CURRENT DATA POINTERMTRDRV MOV R11,@SUBRTN SAVE ROUTINE RETURN ADDRESS CLR R1READB MOV @DATLOC,R8 MOVB *R8,R3 GET BYTE FROM STEP DATA A @SEL,R3 SELECT MOTOR MOVB R3,@PIO SEND DATA TO PIO PORT SBO 2 PULSE CLOCK PIN ON 74HC595 TO INPUT DATA BIT SBZ 2 CI R1,7 CHECK IF ENTIRE BYTE SENT JEQ BYTSNDCONT1 INC R1 INCREMENT BYTE COUNTER INC @DATLOC POINT TO THE NEXT BYTE JMP READBBYTSND SBO 3 PULSE LATCH PIN - OUTPUT BYTE.FROM 74HC595 SBZ 3 BL @DELAY CI R4,0 CHECK FOR FORWARD OR REVERSE DIRECTION JLT CONT3 INC R2 POINT TO NEXT SEQUENCE CI R2,4 CHECK IF BEYOND LAST SEQUENCE JEQ CONT4 INC @DATLOC POINT TO THE NEXT SEQUENCE JMP CONT5 GO BACK TO READING BYTESCONT4 CLR R2 MOV @DATORG,@DATLOC POINT TO START OF SEQUENCE JMP CONT5 GO BACK TO READING BYTESCONT3 DEC R2 POINT TO PREVIOUS SEQUENCE CI R2,0 CHECK IF BEYOND START OF SEQUENCE BLOCK JLT CONT6 MOV R2,R6 SLA R6,3 MOV @DATORG,@DATLOC A R6,@DATLOC POINT TO THE PREVIOUS SEQUENCE JMP CONT5CONT6 AI R2,4 POINT TO LAST SEQUENCE IN BLOCK MOV R2,R6 SLA R6,3 MOV @DATORG,@DATLOC A R6,@DATLOC UPDATE SEQUENCE POINTERCONT5 CLR R1 RESET BYTE COUNTER DEC R5 DECREASE STEP COUNTER JNE READB READ ANOTHER SEQUENCE IF STEPS NOT 0 MOV @SUBRTN,R11 OTHERWISE EXIT ROUTINE B *R11******************************************************************************** ********************************************************************************* SHUT DOWN RS232 CARD AND EXITSHTDN SBZ 0 SBZ 7 B @0******************************************************************************** ********************************************************************************* DELAY ROUTINEDELAY MOV R11,@SUBRT1 MOV @DELVAL,R7CNTDN DEC R7 JNE CNTDN MOV @SUBRT1,R11 B *R11******************************************************************************** END
https://youtu.be/NzsKIjqq1qY
Update 10/19/18
So I ran into some issues during the testing process. First it turned out that the long end of the X platform was sagging quite a bit because the wheel assembly I had 3D-printed turned out to be a little shorter than in should be. I thought I'd take it off and add a little wooden insert under the base, but ended up breaking one of the legs...
I thought I'd replace the wheel with a caster ball assembly I got from the Robotshop, but it ended up causing too much wobbling of the X axis which is has a lot of play laterally. You see, a standard wheel will tend to travel in a straight line and resist rotation, but not so with a free caster ball.
So in the end I re-designed the wheel assembly in OpenScad, lengthening it and beefing it up in the process then 3D printing it. It worked quite well and eliminated most of the sagging.
Now for the actual drawing test, I opted to use the XB environment because my main aim was to be able to draw mathematical graphics using the plotter, and using XB for floating point calculations and trigonometry is light years easier than using straight assembly. So I converted my assembly plotter driver to XB use and was also a source of problems because the stepper motors did not work nearly as smoothly from XB as they did from assembly, and I had to tweak a lot of settings to get to work properly.
Plotter driver:
* 2D PLOTTER CONTROL PROGRAM ** OCTOBER 2018 * DEF HOMEXY,HOMEP,PUP,PDOWN,XRIGHT,XLEFT,YUP,YDOWNPIO EQU >5000 PIO PORT ADDRESSDATLOC BSS 2 MOTOR SEQUENCES DATA LOCATIONDATORG BSS 2 START OF MOTOR SEQUENCESSUBRTN BSS 2 SUBROUTINE RETURN ADDRESSSUBRT1 BSS 2 SUBROUTINE RETURN ADDRESSSUBRT2 BSS 2 SUBROUTINE RETURN ADDRESSSUBRT3 BSS 2 SUBROUTINE RETURN ADDRESSSUBRT4 BSS 2 SUBROUTINE RETURN ADDRESSSEL DATA >0400 >0400=X OR Y, >0200=PENXPTR DATA 0 STEP POINTER FOR X MOTORYPTR DATA 0 STEP POINTER FOR Y MOTORPPTR DATA 0 STEP POINTER FOR PEN MOTORDELVAL DATA 50 DELAY COUNTER VALUE * MOTOR ACTIVATION SEQUENCES* X AND PEN MOTORSXPMDAT BYTE >01,>00,>01,>00,>00,>00,>00,>00 BYTE >00,>01,>01,>00,>00,>00,>00,>00 BYTE >00,>01,>00,>01,>00,>00,>00,>00 BYTE >01,>00,>00,>01,>00,>00,>00,>00 * Y MOTORYMDAT BYTE >00,>00,>00,>00,>01,>00,>01,>00 BYTE >00,>00,>00,>00,>00,>01,>01,>00 BYTE >00,>00,>00,>00,>00,>01,>00,>01 BYTE >00,>00,>00,>00,>01,>00,>00,>01 ********************************************************************************* INITIALIZE THE PIO PORTINITRS LI R12,>1300 SELECT CRU ADDRESS OF RS232 CARD SBO 0 ACTIVATE CARD SBO 7 TURN CARD LED ON CLR @PIO CLEAR PIO PORT SBZ 1 SET PIO TO OUTPUT RT******************************************************************************** ********************************************************************************* X RIGHT ROUTINE 10 STEPSXRIGHT BL @INITRS INITIALIZE THE RS232 CARD BL @INITX LI R5,11 11 STEPS BL @FWD MOVE MOTOR MOV R2,@XPTR SAVE STEP SEQUENCE POINTER B @SHTDN******************************************************************************** ********************************************************************************* X LEFT ROUTINE 10 STEPSXLEFT BL @INITRS INITIALIZE THE RS232 CARD BL @INITX LI R5,11 11 STEPS BL @REV MOVE MOTOR MOV R2,@XPTR SAVE STEP SEQUENCE POINTER B @SHTDN******************************************************************************** ********************************************************************************* Y UP ROUTINE 10 STEPSYUP BL @INITRS INITIALIZE THE RS232 CARD BL @INITY LI R5,11 11 STEPS BL @FWD MOVE MOTOR MOV R2,@YPTR SAVE STEP SEQUENCE POINTER B @SHTDN******************************************************************************** ********************************************************************************* Y DOWN ROUTINE 10 STEPSYDOWN BL @INITRS INITIALIZE THE RS232 CARD BL @INITY LI R5,11 11 STEPS BL @REV MOVE MOTOR MOV R2,@YPTR SAVE STEP SEQUENCE POINTER B @SHTDN******************************************************************************** ********************************************************************************* HOME X AND Y MOTORS ROUTINEHOMEXY BL @INITRS INITIALIZE RS232 CARD BL @INITX INITIALIZE X MOTORREDOX TB 2 CHECK IF END OF TRAVEL SWITCH TRIGGERED JNE DONEX IF YES MOVE X MOTOR RIGHT LI R5,1 NUMBER OF STEPS BL @REV MOVE X MOTOR TO LEFT 1 STEP JMP REDOXDONEX MOV R2,@XPTR BL @INITX LI R5,80 NUMBER OF STEPS BL @FWD MOVE X MOTOR 80 STEPS TO RIGHT MOV R2,@XPTR SAVE CURRENT SEQUENCE POINTER BL @INITY INITIALIZE Y MOTORREDOY TB 2 CHECK IF END OF TRAVEL SWITCH TRIGGERED JNE DONEY IF YES MOVE Y MOTOR UP LI R5,1 NUMBER OF STEPS BL @REV MOV Y MOTOR DOWN 1 STEP JMP REDOYDONEY MOV R2,@YPTR BL @INITY LI R5,80 NUMBER OF STEPS BL @FWD MOVE Y MOTOR 80 STEPS UP MOV R2,@YPTR SAVE CURRENT SEQUENCE POINTER B @SHTDN******************************************************************************** ********************************************************************************* PEN DOWN ROUTINEPDOWN BL @INITRS INITIALIZE RS232 CARD BL @INITP INITIALIZE PEN MOTOR LI R5,20 20 STEPS BL @REV MOVE MOTOR MOV R2,@PPTR SAVE CURRENT STEP SEQUENCE POINTER B @SHTDN******************************************************************************** ********************************************************************************* HOME PEN ASSEMBLY ROUTINEHOMEP BL @INITRS INITIALIZE RS232 CARD BL @INITP INITIALIZE PEN MOTORREDOP TB 2 CHECK IF END OF TRAVEL SWITCH TRIGGERED JNE DONEP IF YES THEN EXIT LI R5,1 NUMBER OF STEPS BL @REV MOV PEN MOTOR 1 STEP DOWN JMP REDOPDONEP MOV R2,@PPTR SAVE CURRENT SEQUENCE POINTER BL @INITP LI R5,20 20 STEPS BL @FWD RAISE PEN MOV R2,@PPTR SAVE CURRENT STEP SEQUENCE POINTER B @SHTDN******************************************************************************** ********************************************************************************* RAISE PEN ROUTINEPUP BL @INITRS INITIALIZE RS232 CARD BL @INITP INITIALIZE PEN MOTOR LI R5,20 20 STEPS BL @FWD RAISE PEN UP MOV R2,@PPTR SAVE CURRENT STEP SEQUENCE POINTER B @SHTDN******************************************************************************** ********************************************************************************* INITIALIZE X MOTOR ROUTINEINITX MOV R11,@SUBRT3 LI R1,XPMDAT MOV R1,@DATORG MOV @XPTR,R2 SLA R2,3 A R2,R1 MOV R1,@DATLOC LI R1,>0400 SELECT X/Y CHIP MOV R1,@SEL LI R7,300 SET DELAY MOV R7,@DELVAL MOV @XPTR,R2 MOV @SUBRT3,R11 B *R11******************************************************************************** ********************************************************************************* INITIALIZE Y MOTOR ROUTINEINITY MOV R11,@SUBRT3 LI R1,YMDAT MOV R1,@DATORG MOV @YPTR,R2 SLA R2,3 A R2,R1 MOV R1,@DATLOC LI R1,>0400 MOV R1,@SEL LI R7,300 MOV R7,@DELVAL MOV @YPTR,R2 MOV @SUBRT3,R11 B *R11******************************************************************************** ********************************************************************************* INITIALIZE PEN MOTORINITP MOV R11,@SUBRT3 LI R1,XPMDAT MOV R1,@DATORG MOV @PPTR,R2 SLA R2,3 A R2,R1 MOV R1,@DATLOC LI R1,>0200 MOV R1,@SEL LI R7,400 MOV R7,@DELVAL MOV @PPTR,R2 MOV @SUBRT3,R11 B *R11******************************************************************************** ********************************************************************************* MOVE MOTOR FORWARDFWD MOV R11,@SUBRT2 LI R4,1 FORWARD DIRECTION BL @MTRDRV MOV @SUBRT2,R11 B *R11******************************************************************************** ********************************************************************************* MOVE MOTOR IN REVERSEREV MOV R11,@SUBRT2 LI R4,-1 REVERSE DIRECTION BL @MTRDRV MOV @SUBRT2,R11 B *R11******************************************************************************** ********************************************************************************* MOVE MOTOR ROUTINE* R4 = DIRECTION (1/-1), R5 = NUMBER OF STEPS* R2 = CURRENT DATA POINTERMTRDRV MOV R11,@SUBRTN SAVE ROUTINE RETURN ADDRESS CLR R1READB MOV @DATLOC,R8 MOVB *R8,R3 GET BYTE FROM STEP DATA A @SEL,R3 SELECT MOTOR MOVB R3,@PIO SEND DATA TO PIO PORT SBO 2 PULSE CLOCK PIN ON 74HC595 TO INPUT DATA BIT SBZ 2 CI R1,7 CHECK IF ENTIRE BYTE SENT JEQ BYTSNDCONT1 INC R1 INCREMENT BYTE COUNTER INC @DATLOC POINT TO THE NEXT BYTE JMP READBBYTSND SBO 3 PULSE LATCH PIN - OUTPUT BYTE.FROM 74HC595 SBZ 3 BL @DELAY CI R4,0 CHECK FOR FORWARD OR REVERSE DIRECTION JLT CONT3 INC R2 POINT TO NEXT SEQUENCE CI R2,4 CHECK IF BEYOND LAST SEQUENCE JEQ CONT4 INC @DATLOC POINT TO THE NEXT SEQUENCE JMP CONT5 GO BACK TO READING BYTESCONT4 CLR R2 MOV @DATORG,@DATLOC POINT TO START OF SEQUENCE JMP CONT5 GO BACK TO READING BYTESCONT3 DEC R2 POINT TO PREVIOUS SEQUENCE CI R2,0 CHECK IF BEYOND START OF SEQUENCE BLOCK JLT CONT6 MOV R2,R6 SLA R6,3 MOV @DATORG,@DATLOC A R6,@DATLOC POINT TO THE PREVIOUS SEQUENCE JMP CONT5CONT6 AI R2,4 POINT TO LAST SEQUENCE IN BLOCK MOV R2,R6 SLA R6,3 MOV @DATORG,@DATLOC A R6,@DATLOC UPDATE SEQUENCE POINTERCONT5 CLR R1 RESET BYTE COUNTER DEC R5 DECREASE STEP COUNTER JNE READB READ ANOTHER SEQUENCE IF STEPS NOT 0 MOV @SUBRTN,R11 OTHERWISE EXIT ROUTINE B *R11******************************************************************************** ********************************************************************************* SHUT DOWN RS232 CARD AND RETURN TO XBSHTDN SBZ 0 SBZ 7 LWPI >83E0 B @>006A******************************************************************************** ********************************************************************************* DELAY ROUTINEDELAY MOV R11,@SUBRT1 MOV @DELVAL,R7CNTDN DEC R7 JNE CNTDN MOV @SUBRT1,R11 B *R11******************************************************************************** END
The best way to make sure a plotter is working is to have it draw a circle. So I created an XB test program to do just that using the standard sine/cosine equations for the circle.
The driver includes the following subprograms callable from XB:
- HOMEXY - home the X and Y axes
- HOMEP - home the pen assembly and position the pen holder ready to receive the pen
- XRIGHT and XLEFT - move the X axis to the right or left one unit
- YUP and YDOWN - move the Y axis up or down one unit
- PUP and PDOWN - raise or lower the pen
10 CALL CLEAR20 CALL INIT30 CALL LOAD("DSK5.PDRIVER")40 CALL LINK("HOMEXY")50 CALL LINK("HOMEP")60 PRINT "SECURE PEN"70 CALL KEY(0,K,S) :: IF S=0 THEN 7075 CALL LINK("PUP")80 FOR D=1 TO 590 CALL LINK("XRIGHT")100 NEXT D110 CURX=256 :: CURY=100 :: R=50120 FOR DA=0 TO 360130 RA=DA*PI/180140 TX=INT(R*COS(RA))+100 :: TY=INT(R*SIN(RA))+25150 GOSUB 1000160 NEXT DA170 CALL LINK("HOMEXY")180 STOP1000 REM DRAW POINT1010 DX=CURX-TX :: IF DX<0 THEN DIR=-1 ELSE DIR=11015 IF DX=0 THEN 10501020 FOR D=1 TO ABS(DX)1030 IF DIR=1 THEN CALL LINK("XRIGHT")ELSE CALL LINK("XLEFT")1040 NEXT D1050 DY=CURY-TY :: IF DY<0 THEN DIR=-1 ELSE DIR=11055 IF DY=0 THEN 10901060 FOR D=1 TO ABS(DY)1070 IF DIR=1 THEN CALL LINK("YUP")ELSE CALL LINK("YDOWN")1080 NEXT D1090 CURX=TX :: CURY=TY1095 CALL LINK("PDOWN")1096 CALL LINK("PUP")1100 RETURN
I kept tweaking the driver settings until I got a reasonable circle drawn. Success! From there it should be fairly straightforward to use the callable subprograms from XB to create some interesting mathematical graphics.
https://youtu.be/Idy3Ll67Hmc
So essentially this concludes this project. As far as I am concerned, this was one of the most challenging projects I have tackled to date, particularly the mechanical design side of things. I've learned tremendously though, and that new knowledge will definitely come in handy in the future... There is an added bonus in that the controller board can be very easily hooked up to an Arduino or Raspberry Pi and then be driven by sophisticated drawing software available for these platforms to create smooth artistic patterns like the ones you see online. As it stands now though, while it may seem rather primitive, we have to keep in mind that it is being run by an early home computer over 3 decades old!
Wish list: I still want to have the ability to take a TI Artist image in pattern format and print the bitmap on the plotter. Unfortunately it is way too slow to do in the XB environment, so I am looking at creating a pure assembly program for it although trying to draw every pixel might still be too slow. We'll see how that goes, and if I get decent results I'll post another update
https://youtu.be/C4LmvPvJ2Ww
Summary video of the entire project
Update 10/24/18
I managed to use The Missing Link (extension program for TI Extended Basic with bitmap graphics - The_Missing_Link_2_0.zip) to load a TI Artist pattern _P picture file and send it to the plotter. It does require embedding the TMLEXTRASO (provides additional TML commands - included on the TML disk) and PDRIVER (the plotter assembly driver shown above) into the program using the HMLOADER utility provided with TML, a pretty straighforward process well detailed in the manual.
3 CALL LOAD(8192,250,198)10 CALL LINK("CLEAR")20 CALL LINK("HOMEXY")30 CALL LINK("HOMEP")40 CALL LINK("PRINT",176,1,"SECURE PEN THEN <ENTER>")50 CALL LINK("INPUT",184,1,A$)55 CALL LINK("PUP")60 CALL LINK("CLEAR")70 CALL LINK("PRINT",176,1,"PICTURE PATH.NAME?")80 CALL LINK("INPUT",184,1,N$)90 CALL LINK("LOADP",N$)100 CURX=240 :: CURY=1110 FOR Y=1 TO 192120 FOR X=1 TO 240130 CALL LINK("GETPIX",Y,X,PIXEL)140 IF PIXEL=1 THEN GOSUB 1000150 NEXT X160 NEXT Y170 CALL LINK("HOMEXY")180 STOP1000 REM PIXEL PLOT ROUTINE1010 DX=CURX-X :: IF DX<0 THEN DIR=-1 ELSE DIR=11020 IF DX=0 THEN 10601030 FOR D=1 TO ABS(DX)1040 IF DIR=1 THEN CALL LINK("XRIGHT")ELSE CALL LINK("XLEFT")1050 NEXT D1060 DY=CURY-Y :: IF DY<0 THEN DIR=-1 ELSE DIR=11070 IF DY=0 THEN 11101080 FOR D=1 TO ABS(DY)1090 IF DIR=1 THEN CALL LINK("YDOWN")ELSE CALL LINK("YUP")1100 NEXT D1110 CURX=X :: CURY=Y1120 IF DX=0 AND DY=0 THEN 11501130 CALL LINK("PDOWN")1140 CALL LINK("PUP")1150 RETURN
Line 3 is added by the loader utility, and the embedded assembly code is not visible when the program is listed.
Here's the result printing this iconic image: AEN_P.zip
I'm having too much fun!
Update 11/25/18
Anders Persson pointed out to me that the stepper motor sequence I was using was driving the motors in full steps only, which limits the resolution of the plotter. He provided me with an updated sequence to allow for half-steps, and indeed this worked great with the motors running more smoothly and quieter as well as essentially doubling the plotting area. Below is the complex sine plot in half step, and you will notice how much smaller the drawing is now:
Here's the updated source file:
* 2D PLOTTER CONTROL PROGRAM ** OCTOBER 2018 * DEF HOMEXY,HOMEP,PUP,PDOWN,XRIGHT,XLEFT,YUP,YDOWNPIO EQU >5000 PIO PORT ADDRESSDATLOC BSS 2 MOTOR SEQUENCES DATA LOCATIONDATORG BSS 2 START OF MOTOR SEQUENCESSUBRTN BSS 2 SUBROUTINE RETURN ADDRESSSUBRT1 BSS 2 SUBROUTINE RETURN ADDRESSSUBRT2 BSS 2 SUBROUTINE RETURN ADDRESSSUBRT3 BSS 2 SUBROUTINE RETURN ADDRESSSUBRT4 BSS 2 SUBROUTINE RETURN ADDRESSSEL DATA >0400 >0400=X OR Y, >0200=PENXPTR DATA 0 STEP POINTER FOR X MOTORYPTR DATA 0 STEP POINTER FOR Y MOTORPPTR DATA 0 STEP POINTER FOR PEN MOTORDELVAL DATA 50 DELAY COUNTER VALUE * MOTOR ACTIVATION SEQUENCES* X AND PEN MOTORSXPMDAT BYTE >01,>00,>00,>00,>00,>00,>00,>00 BYTE >01,>00,>01,>00,>00,>00,>00,>00 BYTE >00,>00,>01,>00,>00,>00,>00,>00 BYTE >00,>01,>01,>00,>00,>00,>00,>00 BYTE >00,>01,>00,>00,>00,>00,>00,>00 BYTE >00,>01,>00,>01,>00,>00,>00,>00 BYTE >00,>00,>00,>01,>00,>00,>00,>00 BYTE >01,>00,>00,>01,>00,>00,>00,>00 * Y MOTORYMDAT BYTE >00,>00,>00,>00,>01,>00,>00,>00 BYTE >00,>00,>00,>00,>01,>00,>01,>00 BYTE >00,>00,>00,>00,>00,>00,>01,>00 BYTE >00,>00,>00,>00,>00,>01,>01,>00 BYTE >00,>00,>00,>00,>00,>01,>00,>00 BYTE >00,>00,>00,>00,>00,>01,>00,>01 BYTE >00,>00,>00,>00,>00,>00,>00,>01 BYTE >00,>00,>00,>00,>01,>00,>00,>01 ********************************************************************************* INITIALIZE THE PIO PORTINITRS LI R12,>1300 SELECT CRU ADDRESS OF RS232 CARD SBO 0 ACTIVATE CARD SBO 7 TURN CARD LED ON CLR @PIO CLEAR PIO PORT SBZ 1 SET PIO TO OUTPUT RT******************************************************************************** ********************************************************************************* X RIGHT ROUTINE 12 STEPSXRIGHT BL @INITRS INITIALIZE THE RS232 CARD BL @INITX LI R5,12 12 STEPS BL @FWD MOVE MOTOR MOV R2,@XPTR SAVE STEP SEQUENCE POINTER B @SHTDN******************************************************************************** ********************************************************************************* X LEFT ROUTINE 12 STEPSXLEFT BL @INITRS INITIALIZE THE RS232 CARD BL @INITX LI R5,12 12 STEPS BL @REV MOVE MOTOR MOV R2,@XPTR SAVE STEP SEQUENCE POINTER B @SHTDN******************************************************************************** ********************************************************************************* Y UP ROUTINE 12 STEPSYUP BL @INITRS INITIALIZE THE RS232 CARD BL @INITY LI R5,12 12 STEPS BL @FWD MOVE MOTOR MOV R2,@YPTR SAVE STEP SEQUENCE POINTER B @SHTDN******************************************************************************** ********************************************************************************* Y DOWN ROUTINE 12 STEPSYDOWN BL @INITRS INITIALIZE THE RS232 CARD BL @INITY LI R5,12 12 STEPS BL @REV MOVE MOTOR MOV R2,@YPTR SAVE STEP SEQUENCE POINTER B @SHTDN******************************************************************************** ********************************************************************************* HOME X AND Y MOTORS ROUTINEHOMEXY BL @INITRS INITIALIZE RS232 CARD BL @INITX INITIALIZE X MOTORREDOX TB 2 CHECK IF END OF TRAVEL SWITCH TRIGGERED JNE DONEX IF YES MOVE X MOTOR RIGHT LI R5,1 NUMBER OF STEPS BL @REV MOVE X MOTOR TO LEFT 1 STEP JMP REDOXDONEX MOV R2,@XPTR BL @INITX LI R5,80 NUMBER OF STEPS BL @FWD MOVE X MOTOR 80 STEPS TO RIGHT MOV R2,@XPTR SAVE CURRENT SEQUENCE POINTER BL @INITY INITIALIZE Y MOTORREDOY TB 2 CHECK IF END OF TRAVEL SWITCH TRIGGERED JNE DONEY IF YES MOVE Y MOTOR UP LI R5,1 NUMBER OF STEPS BL @REV MOV Y MOTOR DOWN 1 STEP JMP REDOYDONEY MOV R2,@YPTR BL @INITY LI R5,80 NUMBER OF STEPS BL @FWD MOVE Y MOTOR 80 STEPS UP MOV R2,@YPTR SAVE CURRENT SEQUENCE POINTER B @SHTDN******************************************************************************** ********************************************************************************* PEN DOWN ROUTINEPDOWN BL @INITRS INITIALIZE RS232 CARD BL @INITP INITIALIZE PEN MOTOR LI R5,20 20 STEPS BL @REV MOVE MOTOR MOV R2,@PPTR SAVE CURRENT STEP SEQUENCE POINTER B @SHTDN******************************************************************************** ********************************************************************************* HOME PEN ASSEMBLY ROUTINEHOMEP BL @INITRS INITIALIZE RS232 CARD BL @INITP INITIALIZE PEN MOTORREDOP TB 2 CHECK IF END OF TRAVEL SWITCH TRIGGERED JNE DONEP IF YES THEN EXIT LI R5,1 NUMBER OF STEPS BL @REV MOV PEN MOTOR 1 STEP DOWN JMP REDOPDONEP MOV R2,@PPTR SAVE CURRENT SEQUENCE POINTER BL @INITP LI R5,20 20 STEPS BL @FWD RAISE PEN MOV R2,@PPTR SAVE CURRENT STEP SEQUENCE POINTER B @SHTDN******************************************************************************** ********************************************************************************* RAISE PEN ROUTINEPUP BL @INITRS INITIALIZE RS232 CARD BL @INITP INITIALIZE PEN MOTOR LI R5,20 20 STEPS BL @FWD RAISE PEN UP MOV R2,@PPTR SAVE CURRENT STEP SEQUENCE POINTER B @SHTDN******************************************************************************** ********************************************************************************* INITIALIZE X MOTOR ROUTINEINITX MOV R11,@SUBRT3 LI R1,XPMDAT MOV R1,@DATORG MOV @XPTR,R2 SLA R2,3 A R2,R1 MOV R1,@DATLOC LI R1,>0400 SELECT X/Y CHIP MOV R1,@SEL LI R7,300 SET DELAY MOV R7,@DELVAL MOV @XPTR,R2 MOV @SUBRT3,R11 B *R11******************************************************************************** ********************************************************************************* INITIALIZE Y MOTOR ROUTINEINITY MOV R11,@SUBRT3 LI R1,YMDAT MOV R1,@DATORG MOV @YPTR,R2 SLA R2,3 A R2,R1 MOV R1,@DATLOC LI R1,>0400 MOV R1,@SEL LI R7,300 MOV R7,@DELVAL MOV @YPTR,R2 MOV @SUBRT3,R11 B *R11******************************************************************************** ********************************************************************************* INITIALIZE PEN MOTORINITP MOV R11,@SUBRT3 LI R1,XPMDAT MOV R1,@DATORG MOV @PPTR,R2 SLA R2,3 A R2,R1 MOV R1,@DATLOC LI R1,>0200 MOV R1,@SEL LI R7,400 MOV R7,@DELVAL MOV @PPTR,R2 MOV @SUBRT3,R11 B *R11******************************************************************************** ********************************************************************************* MOVE MOTOR FORWARDFWD MOV R11,@SUBRT2 LI R4,1 FORWARD DIRECTION BL @MTRDRV MOV @SUBRT2,R11 B *R11******************************************************************************** ********************************************************************************* MOVE MOTOR IN REVERSEREV MOV R11,@SUBRT2 LI R4,-1 REVERSE DIRECTION BL @MTRDRV MOV @SUBRT2,R11 B *R11******************************************************************************** ********************************************************************************* MOVE MOTOR ROUTINE* R4 = DIRECTION (1/-1), R5 = NUMBER OF STEPS* R2 = CURRENT DATA POINTERMTRDRV MOV R11,@SUBRTN SAVE ROUTINE RETURN ADDRESS CLR R1READB MOV @DATLOC,R8 MOVB *R8,R3 GET BYTE FROM STEP DATA A @SEL,R3 SELECT MOTOR MOVB R3,@PIO SEND DATA TO PIO PORT SBO 2 PULSE CLOCK PIN ON 74HC595 TO INPUT DATA BIT SBZ 2 CI R1,7 CHECK IF ENTIRE BYTE SENT JEQ BYTSNDCONT1 INC R1 INCREMENT BYTE COUNTER INC @DATLOC POINT TO THE NEXT BYTE JMP READBBYTSND SBO 3 PULSE LATCH PIN - OUTPUT BYTE.FROM 74HC595 SBZ 3 BL @DELAY CI R4,0 CHECK FOR FORWARD OR REVERSE DIRECTION JLT CONT3 INC R2 POINT TO NEXT SEQUENCE CI R2,8 CHECK IF BEYOND LAST SEQUENCE JEQ CONT4 INC @DATLOC POINT TO THE NEXT SEQUENCE JMP CONT5 GO BACK TO READING BYTESCONT4 CLR R2 MOV @DATORG,@DATLOC POINT TO START OF SEQUENCE JMP CONT5 GO BACK TO READING BYTESCONT3 DEC R2 POINT TO PREVIOUS SEQUENCE CI R2,0 CHECK IF BEYOND START OF SEQUENCE BLOCK JLT CONT6 MOV R2,R6 SLA R6,3 MOV @DATORG,@DATLOC A R6,@DATLOC POINT TO THE PREVIOUS SEQUENCE JMP CONT5CONT6 AI R2,8 POINT TO LAST SEQUENCE IN BLOCK MOV R2,R6 SLA R6,3 MOV @DATORG,@DATLOC A R6,@DATLOC UPDATE SEQUENCE POINTERCONT5 CLR R1 RESET BYTE COUNTER DEC R5 DECREASE STEP COUNTER JNE READB READ ANOTHER SEQUENCE IF STEPS NOT 0 MOV @SUBRTN,R11 OTHERWISE EXIT ROUTINE B *R11******************************************************************************** ********************************************************************************* SHUT DOWN RS232 CARD AND RETURN TO XBSHTDN SBZ 0 SBZ 7 LWPI >83E0 B @>006A******************************************************************************** ********************************************************************************* DELAY ROUTINEDELAY MOV R11,@SUBRT1 MOV @DELVAL,R7CNTDN DEC R7 JNE CNTDN MOV @SUBRT1,R11 B *R11******************************************************************************** END
Update disk with all the files: PLOTTER.dsk
- 2
10 Comments
Recommended Comments