Introduction: Electronic Motor Control Using Optical Pick Up.
The first instructable I did was the build of a really nice DC motor. This is kind of a second part. It adds electronic control of the motor and gets rid of the brush and cam which limit the original motor.
Basically the design uses a slotted disc and an optical pickup to measure the time then depending on the pots adjusts the magnet timing and duration using a logic level mosfet to switch the magnet.
Step 1: PCB Build and Components List.
So the main part of this modification to the original build is the PCB with a MicroChip PIC12F675 at its heart.
It took a few revisions to get to the final PCB you see in the pictures here. The design features power supply from a deans plug like before but this time there is a 5Volt regulator to supply the PIC. The PIC receives the pulse from the slotted disc via an optical slot detector. this pulse is then timed and the POT's read before working out when to turn on the magnet and for how long. the magnet is the same as before but this time it is turned on by a logic level mosfet. Two LED's show the presence of 5Volts and indicate when the magnet is turned on.
I am going to do another Instructable about making PCB's but it really isn't that hard to do at home.
Step 2: Fitting It All Together.
So let’s look at the difference from this motor to the original. Firstly the original cam and brush assembly is removed. And the rear shaft support replaced for a different design which has a mount for the optical pickup. The cam is replaced for a disc which has 4 slots cut using a junior hacksaw. So with these new bit you can then detect the time of each section. The really clever bit is the PIC 12F675 which is the brains behind the measuring and control. The rest of the original motor is left untouched, however it is worth noting that the new slotted disc is aligned on the shaft so the slots
Step 3: The Program.
This took a bit of head scratching the most obvious method would be simply to detect the slot then wait a certain TIME then turn the magnet on for another TIME then off then wait for the next slot. But that wasn’t going to work very well because the time changes depending on the speed. SO the method I used was to measure the time then use fractions of the time for the delay and magnet on.
So the programs runs basically like this:-
Wait for a low pulse
Start the tmr1
Wait for a high pulse
Wait for the low pulse again
Stop the tmr1
At this point you need to check if the TMR1 overflowed and if it did start again from the beginning. (flic the rotor faster!) If the pulse was within the 16bit tmr range then the program continues.
The TMR1 value is stored as delay_time (only the 8MSB meaning the value is divided by 256)
The TMR1 is reset and started again
The delay_timing is run depending on the value of the delay pot (scaled to 0-31) multiplied by the delay_time
Then the magnet is turned on
Then the delay_on2 is run depending on the magnet pot (scaled to 0-31) multiplied by the delay_time.
Once the timing delay has completed the magnet turns off.
The Pots are read ready for the next cycle.
Then you wait for the next low pulse and start the cycle again.
The A/D conversion is a 10bit conversion with 8 bits held in one register and the other 2 held in another. You choose where to justify left or right and in my case I chose to only bother with the 8 MSB and ignore the 2 LSB, so in affect I am only reading a 8 bit number. This 8 bit number is then file rotated 3 times to reduce the result to 0 – 31.
10 bit = 0000000000 - 111111111 = 0 – 1023
8 bit = 00000000 – 11111111 = 0 – 255
5 bit = 00000 – 11111 = 0 – 31
Step 4: The Three Adjustments.
You can see in the photos that there are three pot to adjust. The first POT(red) adjusts the pulse duration, if you want more speed and power then you give the motor more pulse. You can see the effect on the Green LED as it will be brighter with more pulse. the Blue pot adjust the timing of when the pulse happens, if you have a small pulse then you need to time it correctly or the motor will stop. if you have a large pulse then the timing has to be correct to stop the magnet being on when the rotor passes it. these two adjustments are the same as rotating the cam for the timing and increasing the tension to increase the pulse duration.
The Last POT (yellow) is what i call a "Hit N' Miss" governor, this was inspired by old stationary engine you sometimes see at steam rallies. these engines have a centrifugal governor when the weights are thrown out and they operate a lever which stops the exhaust valve shutting, then on the next few strokes the engine will just pull in fresh air and then pump it out again and only when the speed has reduced will the exhaust valve shut and the cycle contine. So my circuit looks for a time which is so fast and waits for it to slow down. (fast speed = short time, slow speed = long time) this is adjusted by the Yellow POT.
Step 5: Loading the Program and the Full Listing.
The Program is written in BASIC using MikroElektronika programming environment. You can download this software for free but are limited by the program length. This program is under the maximum length so works fine. But i don't use the MikroElekronika software to load the hex file to the PIC instead i use a small USB programmer from PICCIRCUIT and this connects onto the pins where the POTs connect on the PCB meaning i can program the PIC chip in circuit. The program i use is the PICkit 2 v2.55 program which is also free to download. What is nice about doing it this way is that you can test out different programs without having to remove the chip from the PCB.
program motor symbol input_pulse = GPIO.4 symbol start_timer1 = T1CON.TMR1ON = 1 symbol stop_timer1 = T1CON.TMR1ON = 0 symbol timer1_flag = PIR1.TMR1IF symbol timer0_flag = INTCON.T0IF symbol magnet_on = GPIO.5 = 1 symbol magnet_off = GPIO.5 = 0 dim delay_time as byte pot01 as byte pot02 as byte pot03 as byte count as byte tmr1 as word absolute $0e sub procedure init trisio = %00010111 'set input/output 1 = input 0 = output ansel = %00000111 'set digital or analog 1 = analog 0 = digital OSCCAL = OSCCAL ' ASM ' bsf STATUS,RP0 ' call 0x3ff ' movwf OSCCAL ' bcf STATUS,RP0 ' END ASM ' cmcon = %00000111 ' t1con = %00000000 ' PIE1.TMR1IE = 1 'tmr1_enable = PIE1.TMR1IE PIR1.TMR1IF = 0 'tmr1_flag = PIR1.TMR1IF INTCON.T0IE = 1 'tmr0_enable = INTCON.T0IE magnet_off ' end sub ' ' sub procedure ad_adquire (dim ad_channel as byte) ' adcon0 = (ad_channel) ' delay_us(20) ' adcon0.1 = 1 'start conversion lup14: ' if adcon0.1 = 1 then goto lup14 ' end if ' end sub ' ' sub procedure get_ad ' ad_adquire (%00000001) 'AD0 pin 7 pot03 = 255 - adresh 'divide by 32 (from 10bit) value range 0-31 ad_adquire (%00000101) 'AD1 pin 6 pot02 = adresh >>2 'divide by 32 (from 10bit) value range 0-31 ad_adquire (%00001001) 'AD2 pin 5 pot01 = adresh >>3 '8 Bit only end sub ' sub procedure first_pulse ' magnet_off ' stop_timer1 ' tmr1 = 0 ' lup03: ' if input_pulse = 1 then goto lup03 'check if input pulse is high end if 'and if it is loop until it goes low start_timer1 'once it goes low start tmr1 lup04: ' if input_pulse = 0 then goto lup04 'now loop whilst the input pulse is low end if 'which wont be long as its the gap lup05: ' if input_pulse = 1 then goto lup05 'now loop until the pulse stops being high end if ' stop_timer1 'now low again so stop tmr1 end sub ' ' sub procedure set_tmr0(dim option_val as byte) 'this is a timing loop based on the tmr0 tmr0 = 0 'firstly set the timer to zero timer0_flag = 0 'reset the flag tmr0 = 255 - delay_time 'load a value into the timer based on max value - delay option_reg = (option_val) 'set the timer pre scaler lup26: 'then loop untill the timer overflows if timer0_flag = 1 then timer0_flag = 0 'and return to the main program else goto lup26 ' end if ' end sub ' sub procedure delay_timing 'start with a fixed delay time 'set_tmr0(%00000101) 'run the timer with a pre scaler of 1:64 set_tmr0(%00000110) 'run the timer with a pre scaler of 1:32? count = 0 'reset the counter lup28: 'Pot02 is pin 6 if count = pot02 then goto lup30 'check if the counter has reached the value of the end if 'timing pot which has a range from 0 - 31 set_tmr0(%00000000) 'run the timer with a pre scaler of 1:2 count = count + 1 'increment the counter goto lup28 'loop back to check the value against the pot lup30: 'and return if the pot value has been reached end sub ' ' sub procedure delay_on2 'start with a fixed delay time set_tmr0(%00000011) 'run the timer with a pre scaler of 1:16 count = 0 'reset the counter lup18: ' if count = pot01 then goto lup20 'check if the counter has reached the value of the end if 'timing pot which has a range from 0 - 31 set_tmr0(%00000000) 'run the timer with a pre scaler of 1:2 count = count + 1 'increment the counter goto lup18 'loop back to check the value against the pot lup20: 'and return if the pot value has been reached end sub ' main: ' init ' start: ' first_pulse ' if timer1_flag = 1 then timer1_flag = 0 'check if TMR1 has overflowed and if it has goto start 'reset the flag and return to the start end if 'first pulse was to slow start again. lup07: ' delay_time = tmr1h 'delay_time is only the 8 most significate bits of the 16 bit timer tmr1 = 0 'meaning that its divided by 256 start_timer1 'restart the tmr1 for the next 1/4 rev if delay_time < pot03 then 'speed limit section goto lup08 'skip the magnet on section if speed to high end if ' delay_timing ' magnet_on ' delay_on2 ' magnet_off ' lup08: ' get_ad ' if timer1_flag = 1 then timer1_flag = 0 'check wether the time is too slow and tmr1 has overflowed goto start 'go back to the start is pulse is to low end if ' if input_pulse = 1 then goto lup08 'loop whilst the pulse is still high end if ' stop_timer1 ' goto lup07 ' end. '