PWM problem

pyrogaz

Member
I'm working on a combined motor/CVT controller and datalogger. The unit works very well but with one exception, the PWM is unintentionally turned off at regular intervals which seem to coincide with part of the program that manipulates data then sends it to an LCD and datalogger. I realise some commands do interfere with PWM but as far as I can tell I'm not using any of those. I'd be grateful for any suggestions as to what could be causing it.

Code:
'THSYE Picaxe based speed controller, G C-S 13/02/10
'40x2 processor, current limit set by pot, button to initiate.
'Serial output to LCD, serial output to Openlog datalogger

setfreq em16		'processor speed
settimer t1s_16		'sets increment of timestamp recorded to datalogger
low c.2
serout B.7,N2400_16,(254,1) 'clear LCD display
pause 2000
w9=0				'variable for pwm duty set to zero at startup
w27=0				'logging loop counter set to zero
input d.0			'pin for "go" button set as input
input d.1			'pin for pit button
do
high b.3			'loop to ensure lowest gear
pause 5000
low b.3
pause 500
if pind.1=1 then exit	'switching pit button to "off" will exit loop
loop 
goto startup


startup:
w27=w27+1			'periodical logging loop
if w27=500 then
goto serial1
else endif

if pind.1=0 then
goto pit
else endif

if b30>60 then		'check motor temp is OK
goto limphome		'if motor hot goes to low power setting
else endif

if pind.0=1 then		'check if "go" button is pressed
goto minpow			'if not pressed go to power off routine
else
goto currcontrol		'if pressed will go to control loop
endif

limphome:			'allows car to return to pits at low power setting
if pind.0=1 then		'check if "go" button is pressed
goto minpow
else
goto limpcontrol
endif

limpcontrol:

readadc10 0,w0		'toroidal current sensor
readadc10 1,w1		'current limiting rotary pot

w4=w1/18+520			'scale pot reading to match current sensor range

if w0>w4 then powdown		'decide which way to adjust motor power to reach target current
if w0<w4 then powup

pit:

readadc 6,b6		'this subroutine will force the CVT to its lowest 
if b6>140 then		'setting and limit pwm to 25%
high b3
pause 400
low b3
pause 400
else endif
w9=250
pwmout c.2 , 249 , w9
goto startup


currcontrol:

readadc10 0,w0		'toroidal current sensor
readadc10 1,w1		'current limiting rotary pot

w4=w1/13+580			'scale pot reading to match current sensor range


if w0>w4 then powdown		'decide which way to adjust motor power to reach target current
if w0<w4 then powup
if w0=w4 then startup

powdown:

readadc 6, b6
if b6>140 then geardown 
if w9<25 then minpow	'prevents w9 overflowing back
w9=w9-5			'increments w9 downwards to match target current
pwmout C.2 , 249, w9	'sets pwm duty
goto startup

powup:

if w9>975 then maxpow	'prevents w9 overflowing above 1000
w9=w9+5			'increments w9 upwards to match target current
pwmout C.2 , 249, w9	'sets pwm duty

goto startup

cvtcont:
readadc10 0,w0		'toroidal current sensor
readadc10 1,w1		'current limiting rotary pot

w4=w1/13+580			'scale pot reading to match current sensor range

if w0>w4 then geardown		'decide which way to adjust motor power to reach target current
if w0<w4 then gearup
if w0=w4 then startup

geardown:
high b.3			'blip CVT actuator to give a small change of ratio
pause 400
low b.3
pause 400
goto startup

gearup:
high b.4
pause 400			'blip CVT actuator to give a small change of ratio
low b.4
pause 400
goto startup

maxpow:
if w9=1000 then		'If PWM is at 100% the current will be below the target
goto gearup 		'setting so gear ratio will be increased to put more 
else endif			'load on the motor 
w9=1000			'puts pwm to maximum setting
pwmout C.2 , 249, w9
goto startup

minpow:

w9=0				'puts pwm to minimum setting
pwmout C.2 , 249, w9
goto startup

serial1:
readadc10 0,w0		'toroidal current sensor, re-reads this sensor otherwise will display last reading when "go" button released
readadc10 2,w2		'Battery A potential divider
readadc10 5,w5		'Motor temperature thermistor
readadc 6,b6		'CVT slider pot
if w0<512 then 		'Small fudge to prevent current reading overflowing 
w0=507 else			'downwards at very low values
w0=w0
endif

b20=w0-507*10/51		'calc current digits
b21=w0-507*10//51*10/51	'calc current decimal

b22=w2*2/69			'calc Battery voltage digits
b23=w2*2//69*10/69	'calc Battery voltage decimal

b30=w5-280/8		'calc motor temp
b28=w9/10			'calc % pwm setting


' the following block of code converts byte variables to ascii characters, these
' are then sent by serial output to the lcd. This process overcomes the garbled
' character problem that arises if the lcd receives characters too quickly from
' the picaxe. By converting to ascii the characters are sent individually and 
' slight gap between them gives the lcd firmware chip time to process.
' Note that each byte variable must be split into three ascii variables each
' of a single character, where only one or two of these are required for the 
' display the remainder may be reused in a later conversion.

bintoascii b20,b42,b41,b40		'current digits to b40 & 41
bintoascii b21,b44,b43,b42		'current decimals to b42
bintoascii b22,b45,b44,b43		'battery volt digits to b43 & 44
bintoascii b23,b47,b46,b45		'battery volt decimal to b45	
bintoascii b30,b51,b50,b49		'motor temp to b49 & 50
bintoascii b28,b53,b52,b51		'pwm % to b51, b52 & b53
  

'battery voltages and current for top line of lcd


pause 10
serout B.7,N2400_16,(254,128,b44,b43,".",b45,"V ")
pause 10
serout B.7,N2400_16,(254,134,b41,b40,".",b42,"A ")

'temp and power settings for bottom line of lcd

pause 10
Serout B.7,N2400_16,(254,192,b53,b52,b51,"%")
pause 10
serout B.7,N2400_16,(254,198,b50,b49,"C   ")
pause 10



high d.4		'set pin high prior to sending raw data to openlog
pause 10
serout d.4,t9600_16,(b41,b40,".",b42,",",b44,b43,".",b45,",",b53,b52,b51,",",b50,b49,",",#w1,",",#b6,",",#timer,cr)
'serout d.4,t9600_16,(#w0,",",#w1,",",#w2,",",#w3,",",#w4,",",#w5,",",#w6,",",#w9,",",#timer,cr)
w27=0
goto startup
 

boriz

Senior Member
What I mean is, the serial commands undoubtedly use various internal timers and that could be the source of the conflict. Maybe you could rewrite the code so that the PWM is restarted immediately after every serial command. Just a theory.
 

pyrogaz

Member
Well the code does loop back immediately after the serout commands but seems to be starting from zero duty each time, so I'll try restarting it with the present value of the PWM variable and see what happens, there isn't any mention of Serout interfering with PWM in the manuals.
 

Goeytex

Senior Member
Well the code does loop back immediately after the serout commands but seems to be starting from zero duty each time, so I'll try restarting it with the present value of the PWM variable and see what happens, there isn't any mention of Serout interfering with PWM in the manuals.
Looks like W9 (Duty Cycle) may be going to zero when you are not expecting it to, which in effect turns the PWM off. Too many gotos for me to track down but maybe you could track it down with debug placed in strategic locations.

Or maybe you could insert a line in certain places that tests w9 and then lights an led and pauses if it goes to zero.

Is not likely that serout is causing the problems as it is software serial. I use serout with pwmout quite a bit and have never had a problem with interference.
 
Last edited:

hippy

Ex-Staff (retired)
I don't think SEROUT should be interfering with PWMOUT and I'd suspect that it's a programming issue.

Note that you have 'w9=0' in 'minpow' so once that's been executed your 'if w9 < 25' in 'powdown' when executed forces w9 back to zero again. Only if you've done enough 'powup' to get w9 to 25 or above will you escape the zero. Not sure if that is the problem. Would be worth simulating or putting SERTXD in to see what is going on.
 

pyrogaz

Member
Thanks for all the suggestions, unfortunately my serial to USB cable has failed so will need a new one before I can try a few changes.
 
Top