low frequency PWM Sq wave output

tim123w

New Member
Hi

I am trying to produce a 60hz (with a tolerance of 30hz) sqaure wave 0-5v output from my 40X1 chip to run an LCD. I need to run the rest of the programe at the same time so was planning on using the pwmout but I do not seem to be able to produce a PWM less than 4 khz.
I have 3 questions.
(1) Is it possible to produce less than 4khz PWM with the pwmout?
(2) If you use a pause or wait command does this stop the rest of the programme from running until the pause or wait have completed?
(3) Does anyone have another solution that will not stop the programme from running and will give a consistant output?

Thanks
 

moxhamj

New Member
PWM can't go that low, but pause certainly can and it is quite accurate. But it will lock up the program. You could have shorter pauses eg pause 1 = 1ms and then go and do things in between each one and keep a count of each pause. This will get inaccurate if you have more than a few instructions between each pause. It depends how much other code is running.

Two very simple solutions though would be to use a 555 (cost <$1) or a picaxe 08 ($4) to do the job. I know it is another chip.

I'm sure there is another way - maybe with settimer or some other instruction that sets an internal clock/counter. I just can't find the exact instruction.
 
Last edited:

Dippy

Moderator
You could adjust the PIC internal timer with a POKE (see PIC Data Sheet) but it woul;d affect code running speed, so I'd go along with the Count's idea of a secondary chip.
Or just get a new LCD display. Much easier. Unless you've got somthing very special.
 

slurp

Senior Member
Is it worth using PWMout but putting the signal into a binary (ripple) counter?

I'm sure that these are still being made by TI and the like, you'll have a number of outputs stepping down the frequency in half increments.

4Khz should be able to be tapped at 62.5Hz easily.... either that or go to the next counter bit which whould have been 31Hz (ish) and increase the input frequency from PWMout to bring you back to a more accurate 60Hz.

best regards,
Colin
 

womai

Senior Member
Another option that does not use an additional chip would be to employ the internal timer (the 40X1 has good timer support) and set it up so it launches an interrupt routine 120 times a second. All the interrupt routine does is toggle the output pin and then return. That way, once set up the whole thing runs in the background, and at the same time the signal timing should be pretty stable and accurate no matter what else the 40X1 is doing.

I'd recommend overclocking the 40X1 to 16 MHz because otherwise the interrupt routine may add too much overhead and slow down the rest of the program. Command execution speed at 16 MHz is approx. 8000 commands/sec, so you should get about 60 commands executed between interrupts, i.e. pretty small overhead.

Wolfgang
 

womai

Senior Member
Ok, after a few tries I got the code up and running - see below. From reading the manual I expected that the preload value has to be set only once (and then gets reloaded after every overflow), but it seems you have to set it every time the counter (minor tick) overflows.

In the code, just modify the "EVENTS_PER_SEC" value to change the PWM frequency; due to the overhead in the interrupt routine you need to set it to something slightly higher than twice the desired PWM frequency; a value of 300 produces PWM at 121 Hz in my setup. The "timer-PWM" will run in the background so the main program can do whatever it wants without having to care about the PWM. The PWM signals comes out on output 0.

The code assume you are running the 28X1 (or 40X1) at 16 MHz. If that's not the case, you need to replace the "t1s_16" constant with the appropriate one.

Wolfgang

Code:
' uses internal timer to do slow-speed PWM on pin 0 (needs 28X1)

symbol EVENTS_PER_SEC = 300 ' set to twice the required PWM frequency (actually, slightly higher because of interrupt overhead)

symbol DUMMY_VAL = 65536 - t1s_16
symbol TIMER_PRELOAD_VAL_DIFF = DUMMY_VAL / EVENTS_PER_SEC
symbol TIMER_PRELOAD_VAL = 65536 - TIMER_PRELOAD_VAL_DIFF


setfreq em16

gosub timer_setup

eternal_loop:
    pause 4000 ' sleep for 1 sec, or do something else
goto eternal_loop

interrupt:
    toggle 0 ' do whatever is needed, in this case toggle pin to produce square wave output
    gosub timer_setup
return

timer_setup:
    timer = 0xffff ' generate interrupt at next overflow
    settimer TIMER_PRELOAD_VAL ' preload timer
    setintflags %10000000,%10000000
return
 

Ralpht

New Member
What king of an LCD are you trying to control. I sounds like you have one without a controller chip and need to do all the segment handling yourself.

I have used LCD's that are exactly like the standard 7 segment LED displays and needed the segmen / backplane handling done the hard way. Actually not that hard and my displays had no problems running at about 1.5khz. The 60Hz freq the data sheets mention are more of a minimum spec rather than set in stone. But you should check anyway.

If so then it will be easier to get 1-2 Khz out of PWM from a picaxe than 60Hz.

Is there a reason you don't want to go the extra chip (555 as mentioned by Dr_Acula) ?
 

womai

Senior Member
Ok, figured it out. No need to set the preload value over and over again, I only forgot to clear the timer overflow flag. The updated code is below. Clearing the flag instead of calling settimer again vastly reduces the execution time of the interrupt routine. A "events_per_sec" value of 240 now results in a 118 Hz PWM signal.

Overall, no need to use an external chip (555 or the like), this solution has the Picaxe do everything. At the same time it is applicable to any case where you want to execute a piece of code in the background at regular intervals - as close to multitasking as the Picaxe can get. Just replace the toggle command with anything you like. If you make it a selection based on a counter (you can even use timer modulo some the number of tasks) you can implement (non-preemptive) multitasking in a round-robbin manner, i.e. first interrupt calls subroutine 0, second calls subroutine 1, and so on, then start again with subroutine 0. The only requirement is that each subroutine MUST be well-behaved, i.e. finish and return before the next interrupt comes in.

Wolfgang


Code:
' uses internal timer to do slow-speed PWM on pin 0 (needs 28X1)

symbol EVENTS_PER_SEC = 240 ' set to twice the required PWM frequency (actually, slightly higher because of interrupt overhead)

symbol DUMMY_VAL = 65536 - t1s_16
symbol TIMER_PRELOAD_VAL_DIFF = DUMMY_VAL / EVENTS_PER_SEC
symbol TIMER_PRELOAD_VAL = 65536 - TIMER_PRELOAD_VAL_DIFF


setfreq em16

settimer TIMER_PRELOAD_VAL ' set time preload value
gosub timer_setup

eternal_loop:
    pause 4000 ' sleep for 1 sec, or do something else
goto eternal_loop

interrupt:
    toggle 0 ' do whatever is needed, in this case toggle pin to produce square wave output
    gosub timer_setup
return

timer_setup:
    timer = 0xffff ' generate interrupt at next overflow
    toflag = 0 ' clear timer overflow flag
    setintflags %10000000,%10000000 ' interrupt on timer overflow
return
 

rbwilliams

New Member
I asked this in Code Snippets, but I thought I'd try it here as well.
I really like your code. But I don't understand it very well. I tried it in the SIM, but it keeps erring out.


I understand that you are doing a subroutine that toggles the pin. Cool. The timing of this subroutine is based on subroutine timersetup? That I don't get. And does it never go back to interrupt?
Also, What is T1s_16?

Thanks,
Roger
 

leftyretro

New Member
Ok, figured it out. No need to set the preload value over and over again, I only forgot to clear the timer overflow flag. The updated code is below. Clearing the flag instead of calling settimer again vastly reduces the execution time of the interrupt routine. A "events_per_sec" value of 240 now results in a 118 Hz PWM signal.

Overall, no need to use an external chip (555 or the like), this solution has the Picaxe do everything. At the same time it is applicable to any case where you want to execute a piece of code in the background at regular intervals - as close to multitasking as the Picaxe can get. Just replace the toggle command with anything you like. If you make it a selection based on a counter (you can even use timer modulo some the number of tasks) you can implement (non-preemptive) multitasking in a round-robbin manner, i.e. first interrupt calls subroutine 0, second calls subroutine 1, and so on, then start again with subroutine 0. The only requirement is that each subroutine MUST be well-behaved, i.e. finish and return before the next interrupt comes in.

Wolfgang


Code:
' uses internal timer to do slow-speed PWM on pin 0 (needs 28X1)
 
symbol EVENTS_PER_SEC = 240 ' set to twice the required PWM frequency (actually, slightly higher because of interrupt overhead)
 
symbol DUMMY_VAL = 65536 - t1s_16
symbol TIMER_PRELOAD_VAL_DIFF = DUMMY_VAL / EVENTS_PER_SEC
symbol TIMER_PRELOAD_VAL = 65536 - TIMER_PRELOAD_VAL_DIFF
 
 
setfreq em16
 
settimer TIMER_PRELOAD_VAL ' set time preload value
gosub timer_setup
 
eternal_loop:
    pause 4000 ' sleep for 1 sec, or do something else
goto eternal_loop
 
interrupt:
    toggle 0 ' do whatever is needed, in this case toggle pin to produce square wave output
    gosub timer_setup
return
 
timer_setup:
    timer = 0xffff ' generate interrupt at next overflow
    toflag = 0 ' clear timer overflow flag
    setintflags %10000000,%10000000 ' interrupt on timer overflow
return
Very nice and useful interrupt routine. About the:

"The only requirement is that each subroutine MUST be well-behaved, i.e. finish and return before the next interrupt comes in."

Aren't interrupts disabled upon entry into the interrupt subroutine and only re-enabled upon leaving the interrupt subroutine? That would imply that any gosub routine called in the interrupt routine could take all the time it needed with out fear of another interrupt being generated. That of course would delay the next "time shareing gosub" routine getting it's time in the sun, but other then that should cause no harm?

Oh course all the gosub routines would have to be well behaved to the extent that they don't execute any "Blocking Instructions" and of course try and return in a reasonable time.
Lefty
 
Last edited:

Michael 2727

Senior Member
I think I got down to 10Hz or even lower by poking the T2CON register ?

See HamRadioAddict's picaxe powered Scooter notes below-
http://www.picaxeforum.co.uk/showthread.php?t=6384

Using this combination and underclocking the picaxe you can get a very
low PWM frequency output.

I think 5-HZ may have been the lowest frequency from memory (don't quote me)
it was a while ago since I was playing with this stuff.
50 - 60 Hz should be easy.
 

radioAK0B

New Member
Low Frequency PWM Sq wave output

Wolfgang Trying to understand all the items in the software solution

Dummy_Val not sure what about term t1s-16 (t1s ????)

the other item I am not sure of is Setfreq em16 (em16)

I have been looking for a way to generate 1 sec pulses out of a PICAXE -18X

Looks like your solution might work for me once I understand it

Thanks, Stan
 

womai

Senior Member
Unfortunately, the 18X can't use this code because it does not have timer interrupts. You really need an 28X1 or 40X1.

em16 is a constant used for setfreq on the 28X1 which tells the program that it should use the external resonator (i.e. not the internal oscillator) which is running at 16 MHz. Not applicable on the 18X because it always uses the internal resonator (which can be set to either 4MHz or 8 MHz).

As to the constant t1s_16, search in the Picaxe Basic manual for its definition. It's simply the necessary timer preload value to get a timer interval of 1 sec when running at 16 MHz oscillator speed.

If you only need one specific frequency, you can also do all the calculations beforehand (e.g. with a handheld calculator) and enter the necessary preload value directly into the code. My symbol statements were meant to simplify the use of my code snippet, since all you have to do is change the value for EVENTS_PER _SEC (IMHO much more intuitive than some crytic preload value) and the Programming Editor will do the calculation for you.

Wolfgang
 
Last edited:

RobertN

Member
Slow pulse out

A low frequency output pulse can be obtained if the code has a constant cycle time less than ½ the output frequency period. For a 50% duty cycle at 60 Hz, a pulsout of 8.33ms would be ½ of the output period, while the code plus an empirically determined pause would complete the other half of the period.

An adjustable output duty cycle (PWM) can be obtained by using a constant, plus variables for pulsout and pause, and maths to maintain a constant period. The duty cycle can not span from 0 to 100%, since the code occupies part of the period.

If the code cycle time is constant and longer than ½ the output period, then an output low and output high appropriately placed in the code along with a pause or two can form a low frequency output.

If the code cycle time is not constant, then a number of pauses may have to be sprinkled about the code in an attempt to maintain a more or less constant duty cycle and frequency.
 
Top