Code to control output On and Off pulse times with pots

Visser

Well-known member
Good day
I need help please. Im using the Picaxe18m2.
I tried to write code to switch an output on and off and the on and off times must be independently controlled by 2 pots on the input.
I use 2 linear 10k pots on adc inputs. I found that the pulse widths only adjust from 0v to about halfway at 2.5v on the wiper of the pots. Further adjustment to 5V does not change anything.
It also seems as if I cant get more than 250ms pulses out . So what i did to get up to 25 sec on and off times was to repeat the pause pulse in both cases 100 times
I can use it like that but surely there must be an easier way to do it or to write the code. Someone that is not available anymore helped me with the original. I studied the commands and changed it a lot as it was not working as it should. To tell you the truth I don't really understand the Symbol statements using W6 etc
Any help will be appreciated
Here is the code I use:
Code:
                let dirsB=%11111111 --------------------- ;B0-7 ALL OUTPUTS
                let dirsC=%00001000 --------------------  ; C0  C1  INPUT (c3 out c4 in)
                let adcsetup=%0000001100000000-------  ;set ADC BIT 8 AND 9   C0 AND C1
                setfreq M32
                Start:
                Symbol  FreqAdj1    = w6   
                Symbol  onpulse      = w7
                Symbol  FreqAdj2     = w8           
                Symbol  offpulse       = w9

                goto Main
                Main:
                do
                readadc10 C.1, w6 --------------------------------   ;Get value from adjust pot. (ON PULSE)          
                onpulse = FreqAdj1 min 0 max 255--------------    ;Make onpulse equal to FreqAdj1.
                readadc10 C.0, w8--------------------------------     ;Get value from adjust pot. (off PULSE)
                offpulse = FreqAdj2 min 0 max 255 -------------     ;Make offpulse equal to FreqAdj2.
                high B.6----------------------------------------------- ;Turn led and Motor FET on
                pause onpulse---------------------------------------- ;Pause for value of onpulse
                low B.6------------------------------------------------  ;Turn led and Motor FET off                
                pause offpulse----------------------------------------  ;Pause for value of offpulse     
                goto main
 
Last edited by a moderator:

lbenson

Senior Member
A couple of extraneous points before getting to your problem. The "goto Main" before "Main:" is unneeded. Because you have the beginning of a "DO ... LOOP" following "Main:", you need to replace the "goto main" at the end with "loop". I'm not certain, but never hitting a "LOOP" statement and repeatedly starting a new "DO" may be causing your program to repeatedly (and silently) crash and restart, which could contribute to your problems.

Regarding your not getting the full range you anticipate, this could be your problem: you do READADC10, which gives a range of 0-1023 values, but then with the next statement, you truncate it to 255--cutting out 3/4ths of your pot range. The easiest solution, if I've understood correctly, is to replace your READADC10 lines with "readadc C.1,onpulse" and "readadc C.0,offpulse" and remove the "FreqAdj" lines. This will give you onpulse and offpulse values between 0 and 255, which seems to be your goal.

Another extraneous point: if you enclose the code which you paste into your posts with the tags "[ code]" and "[ \code]" (without the spaces I've included to keep the forum software from applying those tags), your code will be in a scrollable area and will include any indentation that you have, like this:
Code:
let dirsB=%11111111 '--------------------- ;B0-7 ALL OUTPUTS
let dirsC=%00001000 '-------------------- ; C0 C1 INPUT (c3 out c4 in)
let adcsetup=%0000001100000000 '------- ;set ADC BIT 8 AND 9 C0 AND C1
setfreq M32
Start:
Symbol FreqAdj1 = w6
Symbol onpulse = w7
Symbol FreqAdj2 = w8
Symbol offpulse = w9

Main:
  do
    readadc C.1, onpulse '-------------------------------- ;Get value from adjust pot. (ON PULSE)
    readadc C.0, offpulse '-------------------------------- ;Get value from adjust pot. (off PULSE)  
    high B.6 '----------------------------------------------- ;Turn led and Motor FET on
    pause onpulse '---------------------------------------- ;Pause for value of onpulse
    low B.6 '------------------------------------------------ ;Turn led and Motor FET off
    pause offpulse '---------------------------------------- ;Pause for value of offpulse
  loop
Note that your pauses will be very short--from 0ms to 255ms--max a quarter of a second. You may want to scale them at least for testing with an LED by, say, multiplying onpulse and offpulse by 10 or more.
 
Last edited:

hippy

Technical Support
Staff member
Welcome to the PICAXE forum.

I think part of the issue is in being new to the PICAXE and using things which you are not familiar with. The best advice is to start simple and work up from there, use more complicated things like SYMBOL and SETFREQ once you have gained some initial practical experience.

You seem to want to have on and off periods which are about 25 seconds long, or 25000ms. That would seem to map, as lbenson suggests, quite well to the 0-255 reading obtained from READADC using -

period = adc * 100

Your code could then be -
Code:
#Picaxe 18M2
Do
  ReadAdc C.1, w1 : w1 = w1 * 100
  ReadAdc C.0, w0 : w0 = w0 * 100
  High B.6
  Pause w1
  Low B.6
  Pause w0
Loop
That should work quite well for what you want.

The DO and LOOP is just a nicer way of having 'main:' and a 'GOTO main' at the end.

But one thing you will quickly notice with that, when using longer delays, you have to wait for those delays to have completed before any change in pot position is recognised. That can get quite frustrating.

What you can do is rewrite your code in a different way which is 'more responsive'. This code will instantly curtail a delay as the pot is wound down and let it increase it as it is wound up.

Code:
#Picaxe 18M2
Do
  Gosub TurnOn
  Gosub TurnOff
Loop

TurnOn:
  High B.6
  w0 = 0
  Do
    Pause 100
    w0 = w0 + 1
    ReadAdc C.1, w1
  Loop While w0 < w1
  Return 

TurnOff:
  Low B.6
  w0 = 0
  Do
    Pause 100
    w0 = w0 + 1
    ReadAdc C.0, w1
  Loop While w0 < w1
  Return
Don't worry if it's not immediately obvious how that works. Just ask if there is something not clear.

What it basically does is use 'w0' to count how many 100ms pauses there have been, while using 'w1' to determine how many 100ms pauses there should be. Once the number of pauses have been completed the TurnOn and TurnOff subroutines will complete, then on to the other.

Thus a pot set at 250 will require 250 x 100ms pauses, 25000ms in total, 25 seconds.
 

Visser

Well-known member
Thank you for such excellent response
The pulses are indeed short. I used READADC10, which gives a range of 0-1023 values in my original code and of coarse fixed all the other problems you pointed out and that give me 1 sec pulses at full pot position. Oh yes the pots no works full range!!
How will I multiplying onpulse and offpulse by 10 or more without repeating it 10 times in the code?
I dont think I understand your "[ code]" and "[ \code]" point as I should but I tried below
Code:
   "[let dirsB=%11111111"]                               ;B0-7 ALL OUTPUTS
   "[ let dirsC=%00001000"]                             ; C0  C1  INPUT (c3 out c4 in)
   "[ let adcsetup=%0000001100000000"]        ;set ADC BIT 8 AND 9   C0 AND C1
    setfreq M32

Start:
    Symbol  FreqAdj1       = w6    
    Symbol  onpulse         = w7
      Symbol  FreqAdj2     = w8             
    Symbol  offpulse         = w9
   




Main:
   
    do
   "[ readadc10 C.1, w6"]                                      ;Get value from adjust pot. (ON PULSE)   
    "[onpulse = FreqAdj1 min 0 max 1023"]         ;Make onpulse equal to FreqAdj1.
   "[ readadc10 C.0, w8"]                                      ;Get value from adjust pot. (off PULSE)
   "[ offpulse = FreqAdj2 min 0 max 1023"]         ;Make offpulse equal to FreqAdj2. max 250ms  
   "[ high B.6"]                                                       ;Turn led and Motor FET on
   
   "[ pause onpulse"]                       ;Pause for value of onpulse
    pause onpulse               
    pause onpulse              
    pause onpulse              
               
       
   "[ low B.6"]                                 ;Turn led and Motor FET off   
   
   "[ pause offpulse"]                           ;Pause for value of offpulse   
    pause offpulse                         
    pause offpulse                         
    pause offpulse                        
    pause offpulse               
                  
                   
    loop
 
Last edited by a moderator:

hippy

Technical Support
Staff member
The pulses are indeed short. I used READADC10, which gives a range of 0-1023 values in my original code and of coarse fixed all the other problems you pointed out and that give me 1 sec pulses at full pot position.
Part of the problem is using "setfreq m32". That will make all your PAUSE commands 8 times shorter than you want.

You are also setting your "onpulse = FreqAdj1 min 0 max 1023". There is no need for either a min or max as the FreqAdj1 value can only be 0 to 1023 from a READADC10.

What you are doing is making the onpulse value the same as the pot value, giving it a range of 0 to 1023. Then you use that in a PAUSE which pauses in increments of 1ms. With a full pot value of 1023 that means a 1023ms delay, about 1 second, an 1/8th of that due to the SETFREQ M32.

So first thing is to remove the SETFREQ M32, if you haven't already..

Next is to increase the onpulse so it's the right value for PAUSE to deliver the delay you want. If a full pot of 1023 means 25 seconds, 25000ms, you need to multiply FreqAdj1 by approximately 25 : 1023 x 25 = 25575, ~25000ms, ~25 seconds.

Likewise for offpulse.

So your calculations should be -

onpulse = FreqAdj1 * 25
offpulse = FreqAdj2 * 25

Finally, remove multiple "pause onpulse" and multiple "pause offpulse". With the correct onpulse and offpulse values, calculated as above, you will only need one of each.

My previous code modified to work with READADC10 would be -
Code:
#Picaxe 18M2
Do
  ReadAdc10 C.1, w1 : w1 = w1 * 25
  ReadAdc10 C.0, w0 : w0 = w0 * 25
  High B.6
  Pause w1
  Low B.6
  Pause w0
Loop
If you wish to use SYMBOL statements to name the variables -
Code:
#Picaxe 18M2

Symbol FreqAdj1 = w0
Symbol FreqAdj2 = w1
Symbol onpulse  = w2
Symbol offpulse = w3

Do
  ReadAdc10 C.1, FreqAdj1 : onpulse  = FreqAdj1 * 25
  ReadAdc10 C.0, FreqAdj2 : offpulse = FreqAdj2 * 25
  High B.6
  Pause onpulse
  Low B.6
  Pause offpulse
Loop
 

Visser

Well-known member
Don't worry if it's not immediately obvious how that works. Just ask if there is something not clear.

What it basically does is use 'w0' to count how many 100ms pauses there have been, while using 'w1' to determine how many 100ms pauses there should be. Once the number of pauses have been completed the TurnOn and TurnOff subroutines will complete, then on to the other.

Thus a pot set at 250 will require 250 x 100ms pauses, 25000ms in total, 25 seconds.
Part of the problem is using "setfreq m32". That will make all your PAUSE commands 8 times shorter than you want.

You are also setting your "onpulse = FreqAdj1 min 0 max 1023". There is no need for either a min or max as the FreqAdj1 value can only be 0 to 1023 from a READADC10.

What you are doing is making the onpulse value the same as the pot value, giving it a range of 0 to 1023. Then you use that in a PAUSE which pauses in increments of 1ms. With a full pot value of 1023 that means a 1023ms delay, about 1 second, an 1/8th of that due to the SETFREQ M32.

So first thing is to remove the SETFREQ M32, if you haven't already..

Next is to increase the onpulse so it's the right value for PAUSE to deliver the delay you want. If a full pot of 1023 means 25 seconds, 25000ms, you need to multiply FreqAdj1 by approximately 25 : 1023 x 25 = 25575, ~25000ms, ~25 seconds.

Likewise for offpulse.

So your calculations should be -

onpulse = FreqAdj1 * 25
offpulse = FreqAdj2 * 25

Finally, remove multiple "pause onpulse" and multiple "pause offpulse". With the correct onpulse and offpulse values, calculated as above, you will only need one of each.
Absolutely amazing! It works exactly like I didn't even know it can. It is suppose to adjust pulse widths while running in real time but I thought that is not possible.
I build this picaxe board a while ago with 4 outputs to 8 isolated IGBT or fet drivers and need to implement it now only to find out the code I had was not working properly and I also dont have a clue. But to jump in on the deep side always work when I have such awesome people helping.
Very soon I need to measure Rpm of an flywheel with a hall or other sensor and want to be able to tell it to switch an output on or off at certain rpm's. Will that be possible with a picaxe. Everybody tells me to use an Arduino but after what I saw from you guys today I think it will be possible
Thank you to all that helped
Regards
Vissie
 

hippy

Technical Support
Staff member
Very soon I need to measure Rpm of an flywheel with a hall or other sensor and want to be able to tell it to switch an output on or off at certain rpm's. Will that be possible with a picaxe.
Yes, that should be entirely possible with a PICAXE. It may even be as simple as the following which turns on an output when above 60 RPM by counting hall effect sensor pulses over a minute -
Code:
Do
  Count C.0, 60000, rpm
  If rpm > 60 Then
    High B.6
  Else
    Low B.6
  End If
Loop
In practice you will likely want to measure for shorter than a minute long period and there will be issues in doing that, but members here can help with that.
 

Visser

Well-known member
Good. I would like to do it in a very shorter time. Like to switch off the motor the moment it reaches say 4000 Rpm and on again when it reach say 3000 RPM.
I will try and understand the above code tonight by searching in the picaxe pdf's.
Thank you
Yes, that should be entirely possible with a PICAXE. It may even be as simple as the following which turns on an output when above 60 RPM by counting hall effect sensor pulses over a minute -
Code:
Do
  Count C.0, 60000, rpm
  If rpm > 60 Then
    High B.6
  Else
    Low B.6
  End If
Loop
In practice you will likely want to measure for shorter than a minute long period and there will be issues in doing that, but members here can help with that.
Hi
This code gives an error at rpm
Not sure why
 

Visser

Well-known member
Good. I would like to do it in a very shorter time. Like to switch off the motor the moment it reaches say 4000 Rpm and on again when it reach say 3000 RPM.
I will try and understand the above code tonight by searching in the picaxe pdf's.
Thank you

Hi
This code gives an error at rpm
Not sure why
ok I looked at pdf and changed rpm to W1 like they do and now it runs! Not sure why
 

Visser

Well-known member
ok I looked at pdf and changed rpm to W1 like they do and now it runs! Not sure why
Hi
How does this look. It runs in the simulator but Idont have means to test it yet

#Picaxe 18M2
Do
Count C.0, 1000, w1 ; count pulses in 1secs (at 4MHz)
If w1 < 67 Then ; if rpm < 4020 (87*60)
High B.6
End If
Count C.0, 1000, w1
If w1 > 84 Then ; if rpm > 5040 (84*60)
Low B.6
End If
Loop
 

lbenson

Senior Member
"rpm" is a symbol which, when properly defined, can be used instead of a named variable (b0, w1, etc.) to make it easier for others (and for you at a later time) to understand what the code is supposed to do. You make the association between a symbol and a named variable with a command like "symbol rpm=w1".

When posting, to get your code enclosed in a box, with indentation preserved, put "[ code]" before the first line of your code in the post, and "[ /code]" after the last line (omitting the spaces).

In what you have posted, you don't need to read the count again, you can use an "else" to test the second condition if the first one isn't true:
Code:
symbol rps=w1 ' revolutions per second
do
  Count C.0, 1000, rps     ; count pulses in 1secs (at 4MHz)
  If rps < 67 Then         ; if rpm < 4020 (87*60)   
    High B.6
  elseif rps > 84 Then         ; if rpm > 5040 (84*60)
    Low B.6
  End If
Loop
 

hippy

Technical Support
Staff member
Another option is SELECT-CASE ...
Code:
Symbol rps = w1
Do
  Count C.0, 1000, rps
  Select Case rps
    Case < 67 : High B.6 ; rpm < 4020 (67*60) 
    Case > 84 : Low  B.6 ; rpm > 5040 (84*60)
  End Select
Loop
 

Visser

Well-known member
I want to thank both of you for all the help and options. I will test them all and report back at a later stage how it went
 

hippy

Technical Support
Staff member
(Not sure why this thread is still in this section of the forum. :D)
Purely because neither myself or any other moderator had spotted it wasn't in a more appropriate place. Moving in ... 3 ... 2 ... 1 ...
 

Visser

Well-known member
Part of the problem is using "setfreq m32". That will make all your PAUSE commands 8 times shorter than you want.

You are also setting your "onpulse = FreqAdj1 min 0 max 1023". There is no need for either a min or max as the FreqAdj1 value can only be 0 to 1023 from a READADC10.

What you are doing is making the onpulse value the same as the pot value, giving it a range of 0 to 1023. Then you use that in a PAUSE which pauses in increments of 1ms. With a full pot value of 1023 that means a 1023ms delay, about 1 second, an 1/8th of that due to the SETFREQ M32.

So first thing is to remove the SETFREQ M32, if you haven't already..

Next is to increase the onpulse so it's the right value for PAUSE to deliver the delay you want. If a full pot of 1023 means 25 seconds, 25000ms, you need to multiply FreqAdj1 by approximately 25 : 1023 x 25 = 25575, ~25000ms, ~25 seconds.

Likewise for offpulse.

So your calculations should be -

onpulse = FreqAdj1 * 25
offpulse = FreqAdj2 * 25

Finally, remove multiple "pause onpulse" and multiple "pause offpulse". With the correct onpulse and offpulse values, calculated as above, you will only need one of each.

My previous code modified to work with READADC10 would be -
Code:
#Picaxe 18M2
Do
  ReadAdc10 C.1, w1 : w1 = w1 * 25
  ReadAdc10 C.0, w0 : w0 = w0 * 25
  High B.6
  Pause w1
  Low B.6
  Pause w0
Loop
If you wish to use SYMBOL statements to name the variables -
Code:
#Picaxe 18M2

Symbol FreqAdj1 = w0
Symbol FreqAdj2 = w1
Symbol onpulse  = w2
Symbol offpulse = w3

Do
  ReadAdc10 C.1, FreqAdj1 : onpulse  = FreqAdj1 * 25
  ReadAdc10 C.0, FreqAdj2 : offpulse = FreqAdj2 * 25
  High B.6
  Pause onpulse
  Low B.6
  Pause offpulse
Loop
Part of the problem is using "setfreq m32". That will make all your PAUSE commands 8 times shorter than you want.

You are also setting your "onpulse = FreqAdj1 min 0 max 1023". There is no need for either a min or max as the FreqAdj1 value can only be 0 to 1023 from a READADC10.

What you are doing is making the onpulse value the same as the pot value, giving it a range of 0 to 1023. Then you use that in a PAUSE which pauses in increments of 1ms. With a full pot value of 1023 that means a 1023ms delay, about 1 second, an 1/8th of that due to the SETFREQ M32.

So first thing is to remove the SETFREQ M32, if you haven't already..

Next is to increase the onpulse so it's the right value for PAUSE to deliver the delay you want. If a full pot of 1023 means 25 seconds, 25000ms, you need to multiply FreqAdj1 by approximately 25 : 1023 x 25 = 25575, ~25000ms, ~25 seconds.

Likewise for offpulse.

So your calculations should be -

onpulse = FreqAdj1 * 25
offpulse = FreqAdj2 * 25

Finally, remove multiple "pause onpulse" and multiple "pause offpulse". With the correct onpulse and offpulse values, calculated as above, you will only need one of each.

My previous code modified to work with READADC10 would be -
Code:
#Picaxe 18M2
Do
  ReadAdc10 C.1, w1 : w1 = w1 * 25
  ReadAdc10 C.0, w0 : w0 = w0 * 25
  High B.6
  Pause w1
  Low B.6
  Pause w0
Loop
If you wish to use SYMBOL statements to name the variables -
Code:
#Picaxe 18M2

Symbol FreqAdj1 = w0
Symbol FreqAdj2 = w1
Symbol onpulse  = w2
Symbol offpulse = w3

Do
  ReadAdc10 C.1, FreqAdj1 : onpulse  = FreqAdj1 * 25
  ReadAdc10 C.0, FreqAdj2 : offpulse = FreqAdj2 * 25
  High B.6
  Pause onpulse
  Low B.6
  Pause offpulse
Loop
Hi
The above works fantastic. I need the same idea but with shorter pulses
I need about 30ms on and 30ms off pulses but I also need to adjust the freq of about 16 Hz a little bit with one pot. Meaning I need a 50% duty cycle on pulse adjustable from say 10ms to 100ms.
Now I use simple code:
#Picaxe 18M2
main: high B.6
pause 30
low B.6
pause 30
goto main

but would really like to adjust the pulse widths in real time for experimentation purposes.
 

hippy

Technical Support
Staff member
If we are to assume the midpoint of the pot gives 16Hz, approximately 30ms on 30ms off, we can convert a pot reading of 0-255, to 0-100 with ...

ReadAdc POT_ADC, w0
w1 = w0 * 50 / 128

Then we can create a loop which toggles at 3000us +/- 500us with -
Code:
Do
  ReadAdc POT_ADC, w0
  w1 = w0 * 50 / 128
  w2 = 250 + w1
  PauseUs w2
  Toggle OUTPUT_PIN
Loop
 

Visser

Well-known member
If we are to assume the midpoint of the pot gives 16Hz, approximately 30ms on 30ms off, we can convert a pot reading of 0-255, to 0-100 with ...

ReadAdc POT_ADC, w0
w1 = w0 * 50 / 128

Then we can create a loop which toggles at 3000us +/- 500us with -
Code:
Do
  ReadAdc POT_ADC, w0
  w1 = w0 * 50 / 128
  w2 = 250 + w1
  PauseUs w2
  Toggle OUTPUT_PIN
Loop
30ms.JPG
Thank you. I did It like this: I removed the /128 to get to the range I can use
Do
ReadAdc C.1 , w0
w1 = w0 * 50
w2 = 250 + w1
PauseUs w2
Toggle B.6
Loop
Looking on the scope it look as if I can adjust it between 7 and about 300msec
I attached a photo. If you look very carefully you will see the 30ms on and off pulses
 

Visser

Well-known member
If we are to assume the midpoint of the pot gives 16Hz, approximately 30ms on 30ms off, we can convert a pot reading of 0-255, to 0-100 with ...

ReadAdc POT_ADC, w0
w1 = w0 * 50 / 128

Then we can create a loop which toggles at 3000us +/- 500us with -
Code:
Do
  ReadAdc POT_ADC, w0
  w1 = w0 * 50 / 128
  w2 = 250 + w1
  PauseUs w2
  Toggle OUTPUT_PIN
Loop
May I ask why you add 250ms to W2?
 

hippy

Technical Support
Staff member
May I ask why you add 250ms to W2?
The PAUSEUS command works in 10us units so that was supposed to be setting a base delay of 2500 x 10us, 25000us, 25ms. Then we'd add 0ms to 10 ms to that

Unfortunately there's an out by a factor of 10 error in what I gave. Sorry about that. And I also forgot my usual 'untested' caveat.

What was desired is '25000us + 0us' to '25000us + 10000us', giving 25ms-35ms, which in terms of 10us units is '2500 + 0' to '2500 + 1000' ...
Code:
Do
  ReadAdc C.1 , w0
  w1 = w0 * 4             ; w1 = w0 * 1000 / 255 -> 0 to 1000
  w2 = 2500 + w1
  PauseUs w2
  Toggle B.6
Loop
A READADC10 conveniently gives an approximately 0-1000 value so that could be simplified to -
Code:
Do
  ReadAdc10 C.1 , w0
  w2 = 2500 + w0
  PauseUs w2
  Toggle B.6
Loop
 

Visser

Well-known member
Good day
I need help with the PWMOUT wizard
Im trying to get a 4Khz 50% duty cycle signal. Im not sure if I have to tell the program what system clock to use before I choose the clock freq on the wizard
I probably have to as If I use different clock frequencies in the wizard I get different pulses out
The best i could do to get a 4khz , 50% duty cycle was on a 4 Mhz clock and by choosing the duty cycle as 29%. By looking at the signal on scope that is about the nearest I can get to a 50% duty cycle. Its very confusing. I must be doing something very wrong
See the pictures
 

Attachments

lbenson

Senior Member
What do you get when you don't have the DO ... LOOP--just the PWMOUT statement by itself? You don't need to be continually resetting PWMOUT, and the DO ... LOOP itself occupies a fair amount of time--that's the main reason you're not seeing what you expect.
 

Visser

Well-known member
What do you get when you don't have the DO ... LOOP--just the PWMOUT statement by itself? You don't need to be continually resetting PWMOUT, and the DO ... LOOP itself occupies a fair amount of time--that's the main reason you're not seeing what you expect.
If I only use the PWMOUT statement nothing happens so I tried the do and loop
 

Visser

Well-known member
I cannot get an output without using a Do ,Loop or Main, goto main command
Maybe I should go get a new chip
 
Last edited:

hippy

Technical Support
Staff member
If I only use the PWMOUT statement nothing happens so I tried the do and loop
What you probably need is something like ...
Code:
#Picaxe 18M2
PwmOut B.6, 249, 499
Do : Loop
Which sets the PWM going but doesn't terminate the program. I believe a STOP command ( rather than END ) will act as a DO:LOOP.

That worked for me when I tested it on my 18M2.

I did think you could potentially bit-bang 4kHz out of the PICAXE at 32MHz but no; the best one can do is 3.4kHz.
 
Last edited:

Visser

Well-known member
What you probably need is something like ...
Code:
#Picaxe 18M2
PwmOut B.6, 249, 499
Do : Loop
Which sets the PWM going but doesn't terminate the program. I believe a STOP command ( rather than END ) will act as a DO:LOOP.

That worked for me when I tested it on my 18M2.

I did think you could potentially bit-bang 4kHz out of the PICAXE at 32MHz but no; the best one can do is 3.4kHz.
Hi
Thank you. It runs with Do : Loop. The signal on scope measures 250usec which is 4Kz, but the duty cycle is not 50% its more like 25%
 

Attachments

Visser

Well-known member
Hi
Thank you. It runs with Do : Loop. The signal on scope measures 250usec which is 4Kz, but the duty cycle is not 50% its more like 25%
According to my scope this gives me the nearest to 4Khz , 50% duty
#Picaxe 18M2
pwmout pwmdiv4, B.6, 65, 71 ; 3800Hz at 27% @ 4MHz
Do : Loop
 

Attachments

hippy

Technical Support
Staff member
The signal on scope measures 250usec which is 4Kz, but the duty cycle is not 50% its more like 25%
I really can't explain that. It seems absolutely fine when I look at it using my logic analyser -
 

Attachments

hippy

Technical Support
Staff member
And this is what I get for -
Code:
pwmout pwmdiv4, B.6, 65, 71 ; 3800Hz at 27% @ 4MHz
do : loop
 

Attachments

Visser

Well-known member
I really can't explain that. It seems absolutely fine when I look at it using my logic analyser -
Yes that does look good. I went down in frequency and at about 300Hz it starts to display correct on the scope
Could it be the chip that is damaged? I think I will get another one just to make sure
Another question. Is it only possible to make on off pulses from 1msec and longer? Like this
main:
high B.5
pause 1
low B.5
pause 1
goto main
Or can it be done with usec?
 

hippy

Technical Support
Staff member
I would suggest running the following program and seeing what that gives when you have the B.6 PWM out connected to B.7 immediately above it -
Code:
#Picaxe 18M2
#Terminal 4800
#No_Data
PwmOut B.6, 249, 499
Do
  PulsIn B.7, 0, w0
  PulsIn B.7, 1, w1
  w2 = w0 + w1
  SerTxd("H=",#w1,TAB,"L=",#w0,TAB,"T=",#w2,CR,LF)
  Pause 1000
Loop
For me that shows the following which is correct with the resolution PULSIN gives, with the odd +/-1 to be expected -
Code:
H=12  L=12  T=24
H=12  L=13  T=25
H=12  L=12  T=24
H=12  L=12  T=24
H=12  L=13  T=25
 

hippy

Technical Support
Staff member
Could it be the chip that is damaged? I think I will get another one just to make sure
It is possible it could be damaged but would be odd if it is. It's not the sort of damage I would expect. A different chip would probably be the best way to confirm that. If the second chip works then it would seem to suggest there's something wrong with that one.

If it's the same, unless it a Firmware Version issue, one might have to start thinking about the scope or any circuitry you have connected, though both seem unlikely culprits.

The Firmware version I have is PICAXE-18M2+ vD.A

Another question. Is it only possible to make on off pulses from 1msec and longer? Like this
It is, using either PAUSE or PAUSEUS. The problem is though that overhead of each instruction limits how fast you can get a square wave out. It will be fine for low frequencies but caps out at around 3.4kHz without any PAUSE or PAUSEUS -
Code:
#Picaxe 18M2
SetFreq M32
Do
  Toggle B.6
Loop
 

Visser

Well-known member
It is possible it could be damaged but would be odd if it is. It's not the sort of damage I would expect. A different chip would probably be the best way to confirm that. If the second chip works then it would seem to suggest there's something wrong with that one.

If it's the same, unless it a Firmware Version issue, one might have to start thinking about the scope or any circuitry you have connected, though both seem unlikely culprits.

The Firmware version I have is PICAXE-18M2+ vD.A


It is, using either PAUSE or PAUSEUS. The problem is though that overhead of each instruction limits how fast you can get a square wave out. It will be fine for low frequencies but caps out at around 3.4kHz without any PAUSE or PAUSEUS -
Code:
#Picaxe 18M2
SetFreq M32
Do
  Toggle B.6
Loop
Hi Hippy
Im sorry Im only responding now. I was away for a while.
Im also sorry I wasted your time on this matter. I measured wrong! I did my measurement on the output of a isolated mosfet driver that uses an optocoupler 4n35 on its input. That works fine for low frequencies what it was designed for but I suspect the slow rise and fall times causes the problem
When I measure directly on the output of the pixaxe it is accurate
I will try to use a different mosfet driver like FOD3180 to see if I get and more accurate output to the mosfet

I do have another question. Im trying to run a simple inverter from a H bridge mosfet circuit and need 50Hz out. So I need to switch one set of mosfets for 10msec and than immediately the other set for 10 msec
I thought this could work?

#Picaxe 18M2
main:
high B.5
pause 10
low B.5
high B.6
pause 10
low B.6
goto main


Thank you
Regards
Vissie
 

hippy

Technical Support
Staff member
Im also sorry I wasted your time on this matter. I measured wrong!
Don't worry about that. The main aim is to solve any problems there may be, get things working. There always will be wrong alleys gone down.
I need to switch one set of mosfets for 10msec and than immediately the other set for 10 msec
I thought this could work? ...
I can't see any reason it wouldn't, other then the timing maybe not being entirely accurate.

It would help if you could explain in what way it doesn't work, whether it's just the timing which is out or something else.

If it's just a matter of timing then there will be two things at play here; that "PAUSE 10" may not give an entirely accurate 10ms period, and it and the other commands will also have some execution overhead. So your "High B.5 : Pause 10: Low B.5" time will be longer than 10ms, giving less than 50Hz. There's also a slight overhead in the DO ... LOOP which will make the two periods slightly unbalanced.

Some slight delay between turning off B.5/B.6 before turning the other on can be desirable as this avoids shoot-through if it's a H-Bridge circuit. Shoot-through is where both high and low side switches are active at the same time which shorts the +V to 0V which one doesn't want.

The key to getting the timing right and avoiding shoot-through is in the ordering of commands and tweaking the delay times, best done by PAUSEUS rather than PAUSE -
Code:
#Picaxe 18M2
#No_Data
Do
  Low B.5 : High B.6 : PauseUs 869
  Low B.6 : High B.5 : PauseUs 787
Loop
That seemed quite reasonable when I tried it but could do with more tweaking to get each high and low the same length and the frequency to be exactly 50Hz.

Uisng SETFREQ M32 gives much finer control over the timing as each PAUSEUS unit becomes 1.25us rather than 10us. Though one might then have to put a PAUSEUS between the LOW and HIGH to avoid shoot-through. More rough and ready than at 4MHz -
Code:
#Picaxe 18M2
#No_Data
SetFreq M32
Do
  Low B.5 : High B.6 : PauseUs 8000
  Low B.6 : High B.5 : PauseUs 7800
Loop
 

Visser

Well-known member
Don't worry about that. The main aim is to solve any problems there may be, get things working. There always will be wrong alleys gone down.
I can't see any reason it wouldn't, other then the timing maybe not being entirely accurate.

It would help if you could explain in what way it doesn't work, whether it's just the timing which is out or something else.

If it's just a matter of timing then there will be two things at play here; that "PAUSE 10" may not give an entirely accurate 10ms period, and it and the other commands will also have some execution overhead. So your "High B.5 : Pause 10: Low B.5" time will be longer than 10ms, giving less than 50Hz. There's also a slight overhead in the DO ... LOOP which will make the two periods slightly unbalanced.

Some slight delay between turning off B.5/B.6 before turning the other on can be desirable as this avoids shoot-through if it's a H-Bridge circuit. Shoot-through is where both high and low side switches are active at the same time which shorts the +V to 0V which one doesn't want.

The key to getting the timing right and avoiding shoot-through is in the ordering of commands and tweaking the delay times, best done by PAUSEUS rather than PAUSE -
Code:
#Picaxe 18M2
#No_Data
Do
  Low B.5 : High B.6 : PauseUs 869
  Low B.6 : High B.5 : PauseUs 787
Loop
That seemed quite reasonable when I tried it but could do with more tweaking to get each high and low the same length and the frequency to be exactly 50Hz.

Uisng SETFREQ M32 gives much finer control over the timing as each PAUSEUS unit becomes 1.25us rather than 10us. Though one might then have to put a PAUSEUS between the LOW and HIGH to avoid shoot-through. More rough and ready than at 4MHz -
Code:
#Picaxe 18M2
#No_Data
SetFreq M32
Do
  Low B.5 : High B.6 : PauseUs 8000
  Low B.6 : High B.5 : PauseUs 7800
Loop
Awesome . Thank you. I was thinking about that shoot-through problem. Thats why I ask
I will try it and do the necessary adjustments as seen on the scope
What does #No_Data means?
 

hippy

Technical Support
Staff member
What does #No_Data means?
That just means "Don't download to the Data Eeprom", anything which may appear in DATA statements. As we're not using those we don't need to download that data which would be all zeroes. It makes the program download time a little faster.
 

Goeytex

Senior Member
Are you building an ignition controller or an RPM limiter? If you are I have some Picaxe code that may interest you. Let me know and I will dig it out. of my archives.

Counting revolutions is a slow and fairly inaccurate way of measuring RPM. By the time you count enough revolutions to get a decent reading, the actual RPM of the flywheel could have changed. quite a bit. Think race car or motorcycle.

A better way is to use Pulsin and measure the time it takes for the magnet to pass by the hall sensor. ie. measure the time the hall sensor is off and then the time it is on. Add these times together and you have the time it takes for 1 revolution. Then some simple math will give you RPM.

You can also control ignition timing on-the-fly with this method.

Goey
 

Goeytex

Senior Member
Two Questions

1. What are the minimum and maximum RPMs that you need to measure?
2. What type of motor is turning the flywheel ? BLDC 1 or 3 phase?

A Picaxe is limited to WORD variables . So Assuming a chip frequency of 8MHz, Pulsin will time out and return a zero after 65535 * 5 us ( 325 ms). So there is a low RPM limit, depending upon Picaxe Frequency. But there are workarounds to measure lower.

On the high side 12,000 RPM is doable with a Picaxe, but not much more.

If you intend to use the same Picaxe measure the flywheel velocity and to also control a Brushless DC motor with precision it may be
somewhat tricky due to the processor overhead.
 
Top