How to tell PWM to stop

Gramps

Senior Member
Almost got this working correctly but, PWM will not stop when using a pwmduty C.1,0 command.

The manual says:
Function:
Generate a continuous pwm output using the microcontroller’s internal pwm
module. also see the HPWM command, which can produce the equivalent of
pwmout on different output pins.
Information:
This command is different to most other BASIC commands in that the pwmout
runs continuously (in the background) until another pwmout command is sent.
Therefore it can be used, for instance, to continuously drive a motor at varying
speeds. To stop pwmout issue a ‘pwmout pin, off’ (=pwmout pin,0,0) command.
The PWM period = (period + 1) x 4 x resonator speed
(resonator speed for 4MHz = 1/4000000)
The PWM duty cycle = (duty) x resonator speed

To stop pwmout issue a ‘pwmout pin, off’ (=pwmout pin,0,0) command.
BUT
Instead of off we get very low speed "knock".
Appreciate a hand here,
thanks ,Gramps

Code:
;High and Low Limit pot for stearing arm

#picaxe 28X2
#no_data
#no_table
#terminal 9600

symbol speed_control = C.7
symbol val = w1         ; word (16-bit) user variable
symbol pwmPin = C.1

init:
pwmout C.1, 199, 719
main:

readadc C.7, val ; read 10-bit ADC into variable w1

 SerTxd( "PWM output rate", #val, CR, LF )  ;display the rate
	    pause 100
	    
If val < 40 then pwmduty C.1,0
endif
If val < 50 then pwmduty C.1, 239
endif
If val > 60 then pwmduty C.1, 719
endif 
If val > 200 then pwmduty C.1, 239
endif 
If val > 225 then pwmduty C.1,0
endi

goto main
 

Technical

Technical Support
Staff member
Yes, pwmduty only changes the duty cycle when the pwm module is enabled (and 'off' turns it off completely, so a new pwmout command would be required after every off.)
 

Gramps

Senior Member
Try getting rid of this line:

If val < 50 then pwmduty C.1, 239
If I understand correctly, this command is necessary to return the PWM to 90% when the pot is in the center range.
With this line gone here are the results;
Test 1; load the program with pot at mid point and motor starts and runs at 90% duty. Raise the pot to 200 and motor drops slows to 30%. Increase to 225 and motor stops. but will not restart without reloading the program.
Test 2; load the program with pot at mid point and motor runs at 90% duty. Lower the pot to 40 and the motor stops. but again will not restart without reloading.
Test 3; Load the program with the pot at either extreme ( zero or 255) and nothing happens.
 

AllyCat

Senior Member
Hi,

The problem is that the program is executing ALL those PWMDUTY instructions continuously in sequence, so that values which are < 40 or > 225 will "trigger" more than one condition (i.e. < 50 or > 60 and > 200. Possible solutions are to use an IF .. THEN .. ELSE .. ENDIF sequence, or the SELECT ... CASE structure with appropriate ranges set.

Also, (IMHO) the PWMDUTY command is not the most appropriate to use here. It's a complex (and hence slow) instruction, demonstrated by the size of your sample program consuming 225 bytes of program memory (where it would normally be expected to be less than 100 bytes). PWMDUTY is intended specifically to prevent "glitches" when a Duty Cycle is changed (from one active value to another). But these are rarely an issue, particularly with higher PWM frequencies (e.g. those that don't use a PWMDIVxx qualifier). For the cases of Starting or Stopping the PWM, a glitch cannot occur, so PWMOUT is the "correct" command to use. Yes, you will need to use a PWMOUT command after using a PWM... OFF (or 0), but I think you'll find that using PWMOUTs throughout will work perfectly well (and save some program space). ;)

Cheers, Alan.
 

AllyCat

Senior Member
Hi,

It depends if you need to setup an initial value before the main loop (or for the rare occasions when you do need to use a PWMDUTY command). But if you do use a PWM.. OFF command with PWMDUTY commands, then the "init:" would need to be inside the loop. :)

Generally, you might use it to ensure that the motor is NOT running, or has a particular direction and speed at the start. If the PWM is driving a bridge (e.g. to allow both directions) then the initial value might be 50% (e.g. init: PWMOUT C.1 , 199 , 400) to prevent the motor rotating.

But in your example code it will be only just over 100 ms before it gets updated by a value from the loop (except for a val between 50 and 60 ! ).

Cheers, Alan.
 

Jack Burns

New Member
This seems to work in the simulator.

Not sure if SerTxd can be used at the same time as PwmOut when running on the 28X2.

Code:
;High and Low Limit pot for stearing arm

#picaxe 28X2
#no_data
#no_table
#terminal 9600

symbol speed_control = C.7
symbol val = w1         ; word (16-bit) user variable
symbol pwmPin = C.1
Symbol DutyCycles = w2

main:

readadc C.7, val ; read 10-bit ADC into variable w1

 SerTxd( "PWM output rate: ", #val, CR, LF )  ;display the rate
        pause 100
        
Select val
  case < 40
    DutyCycles = 0

  case < 50
    DutyCycles = 239
  
  case > 225
    DutyCycles = 0

  case > 200
    DutyCycles = 239

  Case > 60
    DutyCycles = 719
EndSelect

pwmout C.1,199,DutyCycles
SerTxd( "PWM Duty cycles: ", #DutyCycles, CR, CR, LF )  ;display the DutyCycles

#REM
If val < 40 then pwmduty C.1,0
endif
If val < 50 then pwmduty C.1, 239
endif
If val > 60 then pwmduty C.1, 719
endif
If val > 200 then pwmduty C.1, 239
endif
If val > 225 then pwmduty C.1,0
endif
#ENDREM

goto main
 

Gramps

Senior Member
so PWMOUT is the "correct" command to use.

New code as suggested (i hope)
P.S. getting the exact same results! Motor driver will not shut off!!

Code:
Code:
;High and Low Limit pot for steering arm
;working some
#picaxe 28X2
#no_data
#no_table
;#terminal 9600

symbol speed_control = C.7
symbol val = w1         ; word (16-bit) user variable
symbol pwmPin = C.1

;init:
;pwmout C.1, 199, 719
main:

readadc C.7, val ; read 10-bit ADC into variable w1

 ;SerTxd( "PWM output rate", #val, CR, LF )  ;display the rate
	    pause 100
    
If val < 40 then pwmout C.1,off

endif

If val < 50 then pwmout C.1, 199, 239
endif
If val > 52 then pwmout C.1, 199, 719
endif 
If val > 180 then pwmout C.1, 199, 239
endif 
If val > 225 then pwmout C.1, 0, 0

endif

goto main
[code/]
 

Gramps

Senior Member
This seems to work in the simulator.

Not sure if SerTxd can be used at the same time as PwmOut when running on the 28X2.
Thanks for joining us Jack!
Yes we always disable sertxd to test the code with the hardware.
Just ran your code and the hardware responds perfectly!
Allycat suggested "case" as one of the alternatives but I'm not familiar with it.

We really appreciate the help! but still struggling to understand why "If val < 40 then pwmout C.1,off" doesn't stop the motor driver!!
 

Jack Burns

New Member
It's because the next if statement (if val < 50) immediately switches it back on again.

Code:
If val < 40 then pwmout C.1,off

endif

If val < 50 then pwmout C.1, 199, 239
endif
 

Jack Burns

New Member
Yes adjust the values to the thresholds you need, however the code I posted earlier needs to detect levels in a certain order to work correctly.

This version uses a few more bytes, but is much easier to follow...

Code:
Select val
  case < 40
    DutyCycles = 0

  case 40 to 49  ' <<< SHOULD THIS BE "40 TO 59" SO YOU DON'T HAVE GAPS ?
    DutyCycles = 239
 
  case 60 to 200
    DutyCycles = 719
    
  case 201 to 225
    DutyCycles = 239
    
  case > 225
    DutyCycles = 0
 
EndSelect
 

Bill.b

Senior Member
Why use if or case statements.

pwmout C.1, 199, val

Will give you continuous control of the motor from 0 to 255

Bill
 

Gramps

Senior Member
Will give you continuous control of the motor from 0 to 255
Bill, thanks for posting. I'm away from the hardware right now and don't even have access to the Editor.
Hopefully I can get back to this later
Gramps
 

AllyCat

Senior Member
Hi,
Why use if or case statements.
Indeed, generally I woud prefer to write an "Equation" or "Formula" to convert an Input value to an Output value, rather than "conditional" statements. But at the moment here, constructing the "Formula" looks to be very difficult, if not impossible:

In descriptive terms the function appears to be: "During the middle part of the (input ADC) range, run the motor at a (fast) constant speed; Towards the ends of the range run the motor at a slower constant speed; Further away from the centre (at "Endstops") switch OFF the motor". That's not easy to write as a formula (even assuming steep rates of change at the speed-switching points), and may need to be rewritten if a tiny change is made, for example to an Endstop.

Also, Jack has pointed out that there is a region which is "Undefined". That is probably an error (oversight), but at the moment, it represents Hysteresis in the Transfer Characteristic, that I don't believe can be written into any normal Linear formula. IMHO the next stage is probably to include some more CASE statements to make it clearer what type of Transfer Characteristic is really required.

Cheers, Alan.
 

Gramps

Senior Member
In this project pot variable1 will represent the position of the steering axle and the end stops.
Pot variables2 and 3 will be the two inputs from the magnetic line following sensors.
(Hopefully) all three variables will steer the vehicle as it follows the buried signal line.🤔
 
Top