HOW do i divide a clock source to an output pin in REALTIME? (or close to realtime)

OLDmarty

Senior Member
Hi All,

I thought this would be really easy, but now it seems VERY hard to achieve, or am i just over-thinking the problem?

I would like to monitor a low frequency clock source (maximum of 1khz), fed into a picaxe, then, with some internal maths or logic, create a division of that frequency to be sent out of another pin.

For example, If i use pinA.0 as the clock input, and pinB.0 is the "modified" clock output, how can i easily achieve this?

My first step is to simply divide the incoming clock by 2, so 1khz IN, becomes 500hz OUT.

I started thinking about using the pulsin command, no good, then i thought about using the "count" command, no good.
What other methods can i use to divide the frequency of the incoming clock? without spending too much time in loops or missing clocks and false triggers etc??

This is probably so simple, but it's driving me up the wall now ;-)

Ultimately, i wanted a picaxe to emulate a binary divider function, like a cmos 4024, 4040, 4060 etc....
I want to emulate this function with a picaxe so i have more control of modifying pin divisions when needed, or assign pin outputs to be something 'other' than the usual weighted, 1,2,4,8,16, something more like 1,2,4,128,256 etc


Thanx in advance to those that can enlighten me ;-)
Time for a long sleep now ;-)
 

lbenson

Senior Member
My first step is to simply divide the incoming clock by 2, so 1khz IN, becomes 500hz OUT.
Something like
Code:
#picaxe 08M2
#no_data

do
  if bit0 <> pinC.3 then
    bit0 = pinC.3
    if bit0 = 1 then
      bit1 = bit1 xor 1 ' toggle bit1 every other time pinC.3 goes high
      if bit1  = 1 then
        toggle C.1
      endif
    endif
  endif
loop
Or
Code:
#picaxe 08M2
#no_data

do 
  do while pinC.3 = 0 : loop
  do while pinC.3 = 1 : loop
  do while pinC.3 = 0 : loop
  toggle C.1
  do while pinC.3 = 1 : loop
loop
To divide by 3, add two more "do while" pairs (0 and 1). To divide by more than 3, put the pairs within a "FOR" loop for as many times as you like.
Code:
#picaxe 08M2
#no_data

symbol n = b1
symbol loopCnt = b2
n = 4 ' number to divide input by

do
  for loopCnt = 2 to n
    do while pinC.3 = 0 : loop
    do while pinC.3 = 1 : loop
  next loopCnt
  do while pinC.3 = 0 : loop
  toggle C.1
  do while pinC.3 = 1 : loop
loop
 
Last edited:

Buzby

Senior Member
Hi OldMarty,

First, use a nice fast PICAXE with lots of pins, running at 64MHz.

Configure a full port as outputs. Let's use port D for example.

Then initialise an interrupt on the pin you want to monitor.

Make an empty 'do loop'. ( All the work is going to be done in the interrupt. )

In the interrupt routine just increment portD.

This will make D.0, D.1, D.2 etc. count at 1/2, 1/4, 1/8 etc of the input pin.

This is the easiest way to divide an input frequency. I'm not sure how fast it will go, but it's easy to test.

I'll come up with some more ideas when I've got my hardware up and running.

Cheers,

Buzby
 

Buzby

Senior Member
Something like
Code:
do
  if bit0 <> pinC.3 then
    bit0 = pinC.3
    if bit0 = 1 then
      :
      : etc ...
      :
There is a subtle problem with this piece of code.

It is possible that pinC.3 can change state between the two lines where it is used, thus causing a miscount.

Better to copy pinC.3 to a temporary bit, then use that in the <> and = lines.

( A similar issue caught me out many years ago, and the result was two weeks of head scratching as drums of oil went down the wrong conveyors. )

Cheers,

Buzby
 

OLDmarty

Senior Member
For realtime why not use a CMOS counter CD4018? :confused:
Yes, the 4018 is a powerful/clever chip, but i want to implement everything in a picaxe with far more control & flexibility than a fixed-function cmos chip..

I'm trying my best not to keep adding support chips to a picaxe project.
 

Buzby

Senior Member
Hi Marty,

Here is an example of a program to divide the frequency by non-power-of-2 numbers.

In this code there are three output frequencies.
Pin 7 clocks at 8/16 * input
Pin 5 clocks at 5/16 * input
Pin 0 clocks at 3/16 * input

By making the size of the table any number you can make finer divisions, like 11/107 * input.

Cheers,

Buzby


Code:
[color=Navy]#picaxe [/color][color=Black]40x2[/color]

[color=Green]' Initialise table in scratchpad[/color]
[color=Blue]for [/color][color=Purple]ptr [/color][color=DarkCyan]= [/color][color=Navy]0 [/color][color=Blue]to [/color][color=Navy]15
      [/color][color=Blue]lookup [/color][color=Purple]ptr[/color][color=Black], [/color][color=Blue]([/color][color=Navy]%10100001[/color][color=Black],_
                   [/color][color=Navy]%00000000[/color][color=Black],_
                   [/color][color=Navy]%10100001[/color][color=Black],_
                   [/color][color=Navy]%00000000[/color][color=Black],_
                   [/color][color=Navy]%10100001[/color][color=Black],_
                   [/color][color=Navy]%00000000[/color][color=Black],_
                   [/color][color=Navy]%10100000[/color][color=Black],_
                   [/color][color=Navy]%00000000[/color][color=Black],_
                   [/color][color=Navy]%10100000[/color][color=Black],_
                   [/color][color=Navy]%00000000[/color][color=Black],_
                   [/color][color=Navy]%10000000[/color][color=Black],_
                   [/color][color=Navy]%00000000[/color][color=Black],_
                   [/color][color=Navy]%10000000[/color][color=Black],_
                   [/color][color=Navy]%00000000[/color][color=Black],_
                   [/color][color=Navy]%10000000[/color][color=Black],_
                   [/color][color=Navy]%00000000[/color][color=Blue])[/color][color=Black],_
                   [/color][color=Purple]@ptr [/color]
[color=Blue]next[/color]

[color=Green]' Set output pins direction[/color]
[color=Purple]dirsD [/color][color=DarkCyan]= [/color][color=Navy]$FF[/color]

[color=Green]' Setup interrupt on A.0[/color]
[color=Blue]setint [/color][color=Navy]%00000001[/color][color=Black],[/color][color=Navy]%00000001[/color][color=Black],A[/color]


[color=Green]' Main loop, which does nothing.[/color]
[color=Blue]do
loop[/color]

[color=Green]' On interrupt, copy data from scratchpad to output port[/color]
[color=Blue]interrupt:
      [/color][color=Purple]ptr [/color][color=DarkCyan]= [/color][color=Purple]ptr [/color][color=DarkCyan]& [/color][color=Navy]$0F
      [/color][color=Purple]outpinsD [/color][color=DarkCyan]= [/color][color=Purple]@ptrinc
      [/color][color=Blue]do
      loop until [/color][color=Purple]pinA.0 [/color][color=DarkCyan]= [/color][color=Navy]0
      [/color][color=Blue]setint [/color][color=Navy]%00000001[/color][color=Black],[/color][color=Navy]%00000001[/color][color=Black],A  [/color]
[color=Blue]return[/color]
 

lbenson

Senior Member
It is possible that pinC.3 can change state between the two lines where it is used, thus causing a miscount.
Yes, it is possible, and it is good to point it out, but it won't happen at the 1kHz speed the OP mentioned (depending on what other code the program might be executing).

You can eliminate that particular possibility by replacing "bit0 = pinC.3" with "bit0 = bit0 xor 1", since the change in state of pinC.3 has been detected, and a toggle of bit0 will place it in the appropriate state.

Nice bit of code to divide by 2,4,8,16,32, etc., simultaneously.
 
Last edited:

Buzby

Senior Member
Yes, it is possible, and it is good to point it out, but it won't happen at the 1kHz speed ...
It can happen at any frequency, as high as 1KHz or as low as 0.001Hz.
The signal can change state anytime during the execution of the code, and if that change is 'between' the lines, no matter what frequency, it will cause a miscount.

In this particular application it will not have a great effect, as it will just affect 1 cycle of the output. But if it was a counting application it could lose or gain 1 count, which could have serious consequences. The application I learned my lesson on counted barrels at a rate of about 1 per 30 seconds.

Your 'bit0 = bit0 xor 1' solution is good, and shorter than mine.

Cheers,

Buzby
 

hippy

Technical Support
Staff member
My take on it. Division set to 3 for ease of simulation ...

Code:
#Picaxe 08M2

Symbol IN_PIN  = pinC.3
Symbol OUT_PIN = C.2

Symbol DIVISOR = 3
 
Low OUT_PIN
Do
  Do : Loop Until IN_PIN = 0
  Do : Loop Until IN_PIN = 1
  w0 = w0 + 1 // DIVISOR
  If w0 = 0 Then
    Toggle OUT_PIN
  End If
Loop
 

StefanST

New Member
Yet another one
Code:
; Emulator similar to CD4040
; input C.0
; 15-bit output: port B (low byte) and C.1 to C.7 (high 7bits)

#PICAXE 28X2
dirsB = %11111111
dirsC = %11111110
SETTIMER COUNT 65535    ; 65536-(N-1)  ... first divider is configurable

Start:
   ; Or, you can assign only the required bits
   outpinsB = timer AND %11111111
   outpinsC = timer >> 7 AND %11111110
   goto Start
and 32-bit counter
Code:
; 32-bit counter
; input C.0
; output: Output_MSW, Output_LSW

#PICAXE 28X2
SYMBOL Output_LSW = timer
SYMBOL Output_MSW = w0
input C.0

Output_LSW = 0
Output_MSW = 0
settimer count 65535    ; 65536-1
setintflags %10000000,%10000000

Start:
   ; some processing ...Output_MSW, Output_LSW
   goto Start

Interrupt:
   if toflag = 1 then
      toflag = 0
      inc Output_MSW
   endif

   setintflags %10000000,%10000000
   return
 
Last edited:
Top