Double DC motor control using pulse width modulation

This project is based on the single PWM project. Everything has just been doubled. The circuit diagram is below. The two IRF 630 MOS-FETs are connected to the PWM1 and PWM2 outputs of the Velleman board. The signals from these outputs turns the FETs ON and OFF  at a fairly high frequency. As the average ON and OFF time changes, so does the speed of the motor.

Two relays are used to control the direction of the motors. They are connected to the number 8 and 7 digital outputs of the K8055 USB board. The circuit diagram and a suggested PCB layout are below.


Double pulse width diagram
The pcb layout

The double PWM projectThe circuit board and motors are shown on the right, connected to the K8055. The motors. Two large red round thingies are connected to the axles to make the things more visible.


The program

To produce a pulse modulated waveform on the K8055, one simply writes to the D to A converter. This produced a voltage at the DAC output and the corresponding waveform at the PWM output. Note that writing 255 produces a minimum and 0 a maximum waveform, so don't be surprised when your motor starts turning the minute the board is connected.

SYS K8055_OutputAnalogChannel%,1,255

writes 255 to the DAC channel 1 and this will stop the motor.

SYS K8055_OutputAnalogChannel%,1,0

will run a motor at maximum speed. Values in between these extremes will turn the motor with varying speed. Mind you, the resistance of the gears, the load and the type of motor used will also greatly affect the final speed.

As starting and stopping as well as changing direction can cause a possibly harmful back emf, the program stops and starts the motor by ramping the speed up and down one step at a time. The same happens when you change direction. The current speed is always displayed at the bottom of the menu.

Below is a zip archive with  the BBC BASIC for Windows program file and the executable of the same program, in case you don't have BB4W

K8055_Dual-pwm.zip

and here is a link to a video of the project

Video link


   10 REM K8055_Two-PWM
   20 REM Control two motors using PWM and the Velleman K8055 USB board
   30 REM Version 1.0
   40 REM Jochen Lueg
   50 REM http://roevalley.com
   60 REM February 2012
   70
   80 PROCK8055_init
   90 SYS K8055_CloseDevice%,0
  100 SYS K8055_OpenDevice%, 0
  110
  120 ON ERROR PROCerror
  130
  140 PROCscreen(380,300)
  150 OFF
  160 PROCinit
  170 SYS K8055_OutputAnalogChannel%,1,255
  180 SYS K8055_OutputAnalogChannel%,2,255
  190
  200 PRINT
  210 PRINT "  Motor 1"
  220 PRINT "  Left - Stop - Right  . . . . . A - S - D"
  230 PRINT "  Slower - Faster  . . . . . . . K - L"
  240 PRINT
  250 PRINT "  Motor 2"
  260 PRINT "  Left - Stop - Right  . . . . . Z - X - C"
  270 PRINT "  Slower - Faster  . . . . . . . < - >"
  280 PRINT
  290 PRINT "  Leave the program  . . . . . . Q"
  300
  310 REPEAT
  320   Key$=INKEY$(0)
  330  
  340   REPEAT UNTIL INKEY(0)=-1
  350   IF (Key$="a" OR Key$="A") AND (M1_Direction$="M1_Right" OR M1_State$="M1_Stopped") PROCM1_left
  360   IF (Key$="s" OR Key$="S") AND M1_State$="M1_Running" PROCM1_stop
  370   IF (Key$="d" OR Key$="D") AND (M1_Direction$="M1_Left" OR M1_State$="M1_Stopped") PROCM1_right
  380  
  390   IF (Key$="z" OR Key$="Z") AND (M2_Direction$="M2_Right" OR M2_State$="M2_Stopped") PROCM2_left
  400   IF (Key$="x" OR Key$="X") AND M2_State$="M2_Running" PROCM2_stop
  410   IF (Key$="c" OR Key$="C") AND (M2_Direction$="M2_Left" OR M2_State$="M2_Stopped") PROCM2_right
  420  
  430   IF Key$="k" OR Key$="K" THEN
  440     M1_RunningSpeed%+=1
  450     IF M1_RunningSpeed%>255 M1_RunningSpeed%=255
  460     SYS K8055_OutputAnalogChannel%,1,M1_RunningSpeed%
  470     M1_StartSpeed%=M1_RunningSpeed%
  480     REPEAT UNTIL INKEY(0)=-1
  490   ENDIF
  500   IF Key$="l" OR Key$="L" THEN
  510     M1_RunningSpeed%-=1
  520     IF M1_RunningSpeed%<0 M1_RunningSpeed%=0
  530     SYS K8055_OutputAnalogChannel%,1,M1_RunningSpeed%
  540     M1_StartSpeed%=M1_RunningSpeed%
  550     REPEAT UNTIL INKEY(0)=-1
  560   ENDIF
  570  
  580   IF Key$="," OR Key$="<" THEN
  590     M2_RunningSpeed%+=1
  600     IF M2_RunningSpeed%>255 M2_RunningSpeed%=255
  610     SYS K8055_OutputAnalogChannel%,2,M2_RunningSpeed%
  620     M2_StartSpeed%=M2_RunningSpeed%
  630     REPEAT UNTIL INKEY(0)=-1
  640   ENDIF
  650   IF Key$="." OR Key$=">" THEN
  660     M2_RunningSpeed%-=1
  670     IF M2_RunningSpeed%<0 M2_RunningSpeed%=0
  680     SYS K8055_OutputAnalogChannel%,2,M2_RunningSpeed%
  690     M2_StartSpeed%=M2_RunningSpeed%
  700     REPEAT UNTIL INKEY(0)=-1
  710   ENDIF
  720   PROCfeedback(M1_RunningSpeed%,M2_RunningSpeed%)
  730  
  740  
  750 UNTIL Key$="q" OR Key$="Q"
  760
  770 PROCM1_stop:PROCM2_stop
  780 SYS K8055_ClearAllDigital%
  790 SYS K8055_OutputAnalogChannel%,1,255
  800 SYS K8055_OutputAnalogChannel%,2,255
  810 SYS K8055_CloseDevice%
  820 SYS "FreeLibrary",K8055_Board%
  830 *QUIT
  840 END
  850
  860
  870
  880 DEFPROCfeedback(Speed1%,Speed2%)
  890 LOCAL S%
  900 COLOUR 6
  910 S1%=(255-Speed1%)/2.55
  920 S2%=(255-Speed2%)/2.55
  930
  940 PRINTTAB(2,13)M1_State$;"   ";M1_Direction$;"   Speed:  ";S1%;"    "
  950 PRINTTAB(2,14)M2_State$;"   ";M2_Direction$;"   Speed:  ";S2%;"    "
  960 ENDPROC
  970
  980
  990 DEFPROCM1_right
 1000 PROCM1_stop
 1010 SYS K8055_SetDigitalChannel%,8
 1020 PROCM1_start
 1030 M1_Direction$="M1_Right"
 1040 ENDPROC
 1050
 1060
 1070 DEFPROCM1_left
 1080 PROCM1_stop
 1090 SYS K8055_ClearDigitalChannel%,8
 1100 PROCM1_start
 1110 M1_Direction$="M1_Left"
 1120 ENDPROC
 1130
 1140
 1150 DEFPROCM1_start
 1160 FOR J%= 255 TO M1_StartSpeed% STEP-4
 1170   SYS K8055_OutputAnalogChannel%,1,J%
 1180   PROCfeedback(J%,M2_RunningSpeed%)
 1190 NEXT
 1200 M1_RunningSpeed%=M1_StartSpeed%
 1210 M1_State$="M1_Running"
 1220 ENDPROC
 1230
 1240


1250 DEFPROCM1_stop
 1260 FOR J%= M1_RunningSpeed% TO 255  STEP 4
 1270   SYS K8055_OutputAnalogChannel%,1,J%
 1280   PROCfeedback(J%,M2_RunningSpeed%)
 1290 NEXT
 1300 M1_State$="M1_Stopped"
 1310 M1_RunningSpeed%=255
 1320 ENDPROC
 1330
 1340 DEFPROCM2_start
 1350 FOR J%= 255 TO M1_StartSpeed% STEP-4
 1360   SYS K8055_OutputAnalogChannel%,2,J%
 1370   PROCfeedback(M1_RunningSpeed%,J%)
 1380 NEXT
 1390 M2_RunningSpeed%=M2_StartSpeed%
 1400 M2_State$="M2_Running"
 1410 ENDPROC
 1420
 1430
 1440 DEFPROCM2_stop
 1450 FOR J%= M2_RunningSpeed% TO 255  STEP 4
 1460   SYS K8055_OutputAnalogChannel%,2,J%
 1470   PROCfeedback(M2_RunningSpeed%,J%)
 1480 NEXT
 1490 M2_State$="M2_Stopped"
 1500 M2_RunningSpeed%=255
 1510 ENDPROC
 1520
 1530
 1540 DEFPROCM1_right
 1550 PROCM1_stop
 1560 SYS K8055_SetDigitalChannel%,8
 1570 PROCM1_start
 1580 M1_Direction$="M1_Right"
 1590 ENDPROC
 1600
 1610
 1620 DEFPROCM1_left
 1630 PROCM1_stop
 1640 SYS K8055_ClearDigitalChannel%,8
 1650 PROCM1_start
 1660 M1_Direction$="M1_Left"
 1670 ENDPROC
 1680
 1690
 1700
 1710 DEFPROCM2_right
 1720 PROCM2_stop
 1730 SYS K8055_SetDigitalChannel%,7
 1740 PROCM2_start
 1750 M2_Direction$="M2_Right"
 1760 ENDPROC
 1770
 1780
 1790 DEFPROCM2_left
 1800 PROCM2_stop
 1810 SYS K8055_ClearDigitalChannel%,7
 1820 PROCM2_start
 1830 M2_Direction$="M2_Left"
 1840 ENDPROC
 1850
 1860
 1870 DEFPROCinit
 1880 M1_RunningSpeed%=255
 1890 M1_StartSpeed%=100
 1900 M2_RunningSpeed%=255
 1910 M2_StartSpeed%=100
 1920
 1930 M1_Direction$="M1_Left"
 1940 M1_State$="M1_Stopped"
 1950 M2_Direction$="M2_Left"
 1960 M2_State$="M2_Stopped"
 1970 ENDPROC
 1980
 1990
 2000 DEFPROCscreen(ScreenWidth%,ScreenHeight%)
 2010 COLOUR 128
 2020 CLS
 2030 COLOUR 15
 2040 SYS "SetWindowPos",@hwnd%,-1,0,0,ScreenWidth%,ScreenHeight%,0
 2050 VDU 26
 2060 ENDPROC
 2070
 2080
 2090 DEFPROCerror
 2100 PRINT REPORT$;" at line ";ERL  :
 2110 SYS K8055_ClearAllDigital%,1
 2120 SYS K8055_ClearAllAnalog%,1
 2130 SYS K8055_CloseDevice%,1
 2140 SYS "FreeLibrary",K8055_Board%
 2150 END
 2160 ENDPROC
 2170
 2180
 2190 DEFPROCK8055_init
 2200 REM These are all the system calls in the order found in the manual
 2210 SYS"LoadLibrary","K8055D.dll" TO K8055_Board%
 2220 SYS"GetProcAddress",K8055_Board%,"OpenDevice" TO K8055_OpenDevice%
 2230 SYS"GetProcAddress",K8055_Board%,"CloseDevice" TO K8055_CloseDevice%
 2240 SYS"GetProcAddress",K8055_Board%,"ReadAnalogChannel" TO K8055_ReadAnalogChannel%
 2250 SYS"GetProcAddress",K8055_Board%,"ReadAllAnalog" TO K8055_ReadAllAnalog%
 2260 SYS"GetProcAddress",K8055_Board%,"OutputAnalogChannel" TO K8055_OutputAnalogChannel%
 2270 SYS"GetProcAddress",K8055_Board%,"OutputAllAnalog" TO K8055_OutputAllAnalog%
 2280 SYS"GetProcAddress",K8055_Board%,"ClearAnalogChannel" TO K8055_ClearAnalogChannel%
 2290 SYS"GetProcAddress",K8055_Board%,"ClearAllAnalog" TO K8055_ClearAllAnalog%
 2300 SYS"GetProcAddress",K8055_Board%,"SetAnalogChannel" TO K8055_SetAnalogChannel%
 2310 SYS"GetProcAddress",K8055_Board%,"SetAllAnalog"  TO K8055_SetAllAnalog%
 2320 SYS"GetProcAddress",K8055_Board%,"WriteAllDigital" TO K8055_WriteAllDigital%
 2330 SYS"GetProcAddress",K8055_Board%,"ClearDigitalChannel" TO K8055_ClearDigitalChannel%
 2340 SYS"GetProcAddress",K8055_Board%,"ClearAllDigital" TO K8055_ClearAllDigital%
 2350 SYS"GetProcAddress",K8055_Board%,"SetDigitalChannel" TO K8055_SetDigitalChannel%
 2360 SYS"GetProcAddress",K8055_Board%,"SetAllDigital"  TO K8055_SetAllDigital%
 2370 SYS"GetProcAddress",K8055_Board%,"ReadDigitalChannel" TO K8055_ReadDigitalChannel%
 2380 SYS"GetProcAddress",K8055_Board%,"ReadAllDigital"  TO K8055_ReadAllDigital%
 2390 SYS"GetProcAddress",K8055_Board%,"ResetCounter"  TO K8055_ResetCounter%
 2400 SYS"GetProcAddress",K8055_Board%,"ReadCounter"  TO K8055_ReadCounter%
 2410 SYS"GetProcAddress",K8055_Board%,"SedtCounterDebouceTime"  TO K8055_SetCounterDebounceTime%
 2420 ENDPROC
 


Return to the interfacing index

Back to the Limavady home page

Tudor with sign