Cadence Meter W/ PICAXE 08M2 & OLED

Tobie Calvert

New Member
Hello,
I'm currently in the depths of coding a program in PICAXE programming editor and I've come across a little issue. I'm going to be deadly honest and say I haven't really got a clue what I'm doing. The code is supposed to take an input from a proximity switch and times that number by the circumference of the bike wheel and display the distance on the PICAXE OLED screen. I can't seem to get the correct cadence to display on the OLED. I'm not massively sure but it may be due to that fact I can't seem to get a variable to display on the OLED. To be honest I'm not even sure if my code is correct.

Any help would be massively appreciated, take care and I look forward to hearing back from you
- Below is attached my trial code
- I'm using an 08M2
- OLED is connected to C.1
- Promsixy Sensor is connected to C.2

Many Thanks,
Tobie
 

Attachments

stan74

Senior Member
screen: serout C.1,N2400,(254,128) ; move to start of first line
serout C.1,N2400,("Cadence in KM:") ; output text
screen2: serout C.1, N2400, (254,192)
serout C.1, N2400, (#b0)
next
try sertxd (#bo,cr,lf) to see what's happening in the terminal. May be the display code isn't working. A hall sensor near the crank like my bikes?
 

hippy

Technical Support
Staff member
Welcome to the PICAXE Forum.

When I load your source code it seems something may have got mangled in the 'DisplayCadence:' and 'Init:' parts so won't pass Syntax Check, and "Init" has become a part of the 'DisplayCadence:' FOR-NEXT loop.
 

stan74

Senior Member
What oled? My cheapo £3 128x64 is i2c. I have a ring of magnets on the pedal crank and a hall sensor to start the motor on my bike. 1 bike, a bewo motor has a brill lcd,cadence,calories,speed,volts,amps,watt/hours,time etc. display,the other a tonaro, has no display but similar crank pulses.
 

hippy

Technical Support
Staff member
What oled?
From the source code it would appear to be an AXE133 or similar and the project is self designed to count pulses from a sensor and then display that count on screen.

We try to make the forum as friendly as we can towards everyone but particularly new members who are probably new to PICAXE and aren't always confident in what they are doing, may not have experienced forums before and may find coming to ask for help a little daunting, so it is reasonable to give some leeway when they are not always immediately clear on some aspects of the problem at hand.

What set-up anyone else has and what that can do is rather off-topic in that respect, just clouds the issue. It may be interesting but isn't entirely useful when someone is seeking to solve their problem.
 

stan74

Senior Member
I thought bike hippy. Tobie Calvert is using an oled and can't display a variable so it's a probably a display problem and didn't see "axe oled". ps I thought cadence was how much I pedalled. Mine are called cadence sensors. The spoke sensor is for counting wheel revs. There might be some hard sums in there for you :)
 

westaust55

Moderator
Yes, my understanding of "Cadence" is the rate/speed the pedals rotate.
Aim being to use the gears to pedal at a constant cadence.
On a bike with gears there is no easy correlation to wheel diameter or rotation.


So two aspects:
1. Is it pedal cadence or bike speed to be determined
2. Getting the display working


EDIT:
Further, the code includes the lines:
Code:
symbol PulsesInSecond = w1 
symbol RotationInMin = w2


TheCalcu:
RotationInMin = PulsesInSecond * 60
therefore the RotationInMin is held in word variable W2
yet the display routine is trying to output the value in byte variable b0\

In the BASIC program provided at post 1 the calculation is incomplete with the line:
Code:
b0 =
will likely not pass the PE syntax check but if it does variable b0 will always have a value like zero (0).
 
Last edited:

Tobie Calvert

New Member
Hello westaust55,

I do apologise, I may have gotten the two words muddled up. I want to design a piece of code which will count the times an input is triggered (the magnet on the bike wheel when it comes into contact with the proximity sensor) and then have the code times the number of inputs by the circumference of the wheel to give the distance. I'm just struggling with getting the code to work. Could you give me any heads up on making the code work or do you think this is too ambitious for a beginner such as myself?

Many Thanks,

Tobie,
 

stan74

Senior Member
I googled picaxe cycle spee and got this http://www.picaxeforum.co.uk/archive/index.php/t-4703.html Before using gode work out the circumference of the TYRE! then divide a mile by it and that's how many turns or pulses for a mile.
Is the oled working ok,does example code display anything?
What sensor,hall,reed relay?
You don't need pulsin,just test a port going lowif that what the sensor does... if c.2=0 then inc counter.
 

AllyCat

Senior Member
Hi tobie,

Welcome to the forum. No it's not too ambitious, there are people here who will help you through. ;)

It may seem surprising, but COUNT is not really the best instruction to use in this application. You are not going to get many "events" (pulses) in one second, and then there is the risk that the program will miss one whilst it is sending data to the display.

If the pulses are pedal wheel-rotations, then the PICaxe is fast enough to count every single one as part of a software loop. There are many ways to test for an event, but probably the easiest is PULSIN, but you must set its polarity so that it responds to the narrow pulse when the sensor is activated, not to the long period (almost one rotation of the pedals wheel ?) between pulses.

You don't need to know the exact value returned by PULSIN, only if it is zero which means that no pulse was detected (so go back and try again). Each time a pulse is detected, then add 1 to your "event" counter. Then there is probably enough time to calculate the current distance and display it on the OLED before another pulse occurs.

To calculate the distance, you need to multiply the number of pulses by the distance per pulse (i.e. the circumference of the wheel). But calculating in inches (or centimetres) will not produce a "useful" result for very long, because the result will soon overflow the calculation range of a PICaxe. The ** operator can give the best result, but that's a little advanced for now, so perhaps start by simply displaying pedal wheel rotations on your OLED.

Cheers, Alan.
 
Last edited:

stan74

Senior Member
"I'm not massively sure but it may be due to that fact I can't seem to get a variable to display on the OLED."
I would try doing that 1st Tobie before the rest. Get familiar with the display 1st, get it to display text etc.
Test the sensor with a multimeter to make sure the magnet is close enough or you'll be wondering why you program isn't working.
Alan,let's keep it simple, not possibilities of pin interrupt events. :) and it's the tyre tread circumference. The tread on my bike is 5 CM from the rim.
The speedo on my bike works walking 3-3.5 mph, 2 wheel rev/S and only a few revs to start so that's the "goal".Time comes in it somewhere.
 
Last edited:

stevesmythe

Senior Member
Alan, despite the thread title,the OP clarified in post #9 that he actually wants to measure distance, not cadence. With your approach (crank sensor), it would only work on a single-geared bike (unless you had a way of knowing which gear you are in and adjusting the distance travelled accordingly)!
 

stan74

Senior Member
26 inch wheel circumference=210 inches, 63360 inches in a mile,3 revs=630 inches so 3 revs=0.01 miles.
if 3 pulses/S then that's 3600 seconds / 0.01 miles=36 or is my math wrong?
Code:
[color=Navy]#picaxe [/color][color=Black]08m2[/color]
[color=Green]; magnet=c.1[/color]
[color=Blue]symbol [/color][color=Purple]counter[/color][color=DarkCyan]=[/color][color=Purple]w0[/color]
[color=Blue]symbol [/color][color=Purple]speed[/color][color=DarkCyan]=[/color][color=Purple]b2
TIME[/color][color=DarkCyan]=[/color][color=Navy]0[/color]
[color=Black]main:[/color]
[color=Blue]if [/color][color=Purple]pinc.1[/color][color=DarkCyan]=[/color][color=Navy]1 [/color][color=Blue]then
      inc [/color][color=Purple]counter
      [/color][color=Blue]do while [/color][color=Purple]pinc.1[/color][color=DarkCyan]=[/color][color=Navy]1 [/color][color=Green]; wait for magnet to pass sensor
      [/color][color=Blue]loop
endif
if [/color][color=Purple]TIME[/color][color=DarkCyan]=[/color][color=Navy]10 [/color][color=Blue]then
      [/color][color=Purple]speed[/color][color=DarkCyan]=[/color][color=Purple]counter[/color][color=DarkCyan]/[/color][color=Navy]30
      [/color][color=Purple]TIME[/color][color=DarkCyan]=[/color][color=Navy]0
      [/color][color=Purple]counter[/color][color=DarkCyan]=[/color][color=Navy]0[/color]
[color=Green];     send speed to oled[/color]
[color=Blue]endif
goto [/color][color=Black]main[/color]
 
Last edited:

AllyCat

Senior Member
Hi,

let's keep it simple, not possibilities of pin interrupt events. :)
Where did I suggest using interrupts! :eek: I never suggest using interrupts to novices, and only use them myself as an absolute last resort. By "event", I meant anything that might "happen": a pulse, an edge, a count, an ADC value exceeding a threshold voltage, or whatever.

But yes, the aim should be break the task down into small, manageable parts: That might be counting pulses (which can be tested on the simulator), writing (O)LED driver code (which also can be tested on the simulator) or debugging OLED display hardware (probably the most difficult for us to help with).

@steve: Ah yes, I see the sensor is (correctly) detecting wheel rotations (my reference to pedals was a slip of the finger ;) ). But, depending where the magnet is located, that may make it even more important to use a clear edge/pulse detection method and not try to "catch" a brief switch-closure within a polling loop.

@stan: Don't know: Has it 26 inch wheels, and with racing or mountain bike tyres?

Cheers, Alan.
 

stevesmythe

Senior Member
Wheel size is measured as the diameter and nominally includes the tyre. So a 26 inch wheel has a diameter of 26 inches and a circumference of pi x 26 = 82 inches. Difference tyre widths affect the effective circumference but, for the sake of this project I would assume 26 inches and then calibrate/adjust the code afterwards.
 
Last edited:

AllyCat

Senior Member
Hi,

I stand corrected; I'm not really a cyclist.

So 776 revolutions per mile? That's why I like ** 8445 (for hundredths of a mile) . ;)

Cheers, Alan.
 

stan74

Senior Member
It's not cadence,it's counting wheel rev/time and my maths is carp.Milage is just Km/tyre circumference counts....I think :)
Does it update every 10 seconds?
This could maybe be at the start of the program,not in the main.
serout C.1,N2400,(254,1)
pause 30
init: pause 500 ; wait for display to initialise
Thinking my speedo displays speed after only a few wheel revolutions so it must measure the time between magnet pulses. You do the sums.
 
Last edited:

stan74

Senior Member
Try this Tobie. The code you posted had c.1 for the sensor and the display.
Code:
[color=Navy]#picaxe [/color][color=Black]08m2[/color]
[color=Green];compiled 91 bytes
; magnet=c.2[/color]
[color=Blue]symbol [/color][color=Purple]counter[/color][color=DarkCyan]=[/color][color=Purple]w0[/color]
[color=Blue]symbol [/color][color=Purple]speed[/color][color=DarkCyan]=[/color][color=Purple]b2[/color]
[color=Blue]symbol [/color][color=Purple]distance[/color][color=DarkCyan]=[/color][color=Purple]b3[/color]
[color=Blue]symbol [/color][color=Purple]metres[/color][color=DarkCyan]=[/color][color=Purple]w2
distance[/color][color=DarkCyan]=[/color][color=Navy]0[/color]
[color=Purple]metres[/color][color=DarkCyan]=[/color][color=Navy]0[/color]
[color=Purple]TIME[/color][color=DarkCyan]=[/color][color=Navy]0[/color]
[color=Green];--wheel circumference=2000mm 2.25" wheel[/color]
[color=Blue]pause [/color][color=Navy]500 [/color][color=Green];moved screen initialise to here[/color]
[color=Blue]serout C.1[/color][color=Black],[/color][color=Blue]N2400[/color][color=Black],[/color][color=Blue]([/color][color=Navy]254[/color][color=Black],[/color][color=Navy]1[/color][color=Blue])
pause [/color][color=Navy]30[/color]
[color=Black]main: [/color]
[color=Blue]if [/color][color=Purple]pinc.2[/color][color=DarkCyan]=[/color][color=Navy]1 [/color][color=Blue]then
      inc [/color][color=Purple]counter [/color][color=Green];count magnet pulses
      [/color][color=Purple]metres[/color][color=DarkCyan]=[/color][color=Purple]metres[/color][color=DarkCyan]+[/color][color=Navy]2[/color][color=Black]:[/color][color=Blue]if [/color][color=Purple]metres[/color][color=DarkCyan]=[/color][color=Navy]1000 [/color][color=Blue]then :inc [/color][color=Purple]distance[/color][color=Black]:[/color][color=Purple]metres[/color][color=DarkCyan]=[/color][color=Navy]0[/color][color=Black]:[/color][color=Blue]endif
      do while [/color][color=Purple]pinc.2[/color][color=DarkCyan]=[/color][color=Navy]1 [/color][color=Green]; wait for magnet to pass sensor
      [/color][color=Blue]loop
endif
if [/color][color=Purple]TIME[/color][color=DarkCyan]=[/color][color=Navy]5 [/color][color=Blue]then [/color][color=Green];5 seconds elapsed
      [/color][color=Purple]speed[/color][color=DarkCyan]=[/color][color=Purple]counter[/color][color=DarkCyan]*[/color][color=Navy]720 [/color][color=Green];wheel circumference*12*60 how many 2M in hour
      [/color][color=Purple]speed[/color][color=DarkCyan]=[/color][color=Navy]1000[/color][color=DarkCyan]/[/color][color=Purple]speed [/color][color=Green];km/H
      [/color][color=Purple]TIME[/color][color=DarkCyan]=[/color][color=Navy]0
      [/color][color=Purple]counter[/color][color=DarkCyan]=[/color][color=Navy]0   
      [/color][color=Black]screen: [/color][color=Blue]serout C.1[/color][color=Black],[/color][color=Blue]N2400[/color][color=Black],[/color][color=Blue]([/color][color=Navy]254[/color][color=Black],[/color][color=Navy]128[/color][color=Blue]) [/color][color=Green]; move to start of first line
      [/color][color=Blue]serout C.1[/color][color=Black],[/color][color=Blue]N2400[/color][color=Black],[/color][color=Blue]([/color][color=Red]"Cadence in KM:"[/color][color=Blue]) [/color][color=Green]; output text
      [/color][color=Black]screen2: [/color][color=Blue]serout C.1[/color][color=Black], [/color][color=Blue]N2400[/color][color=Black], [/color][color=Blue]([/color][color=Navy]254[/color][color=Black],[/color][color=Navy]192[/color][color=Blue])
      serout C.1[/color][color=Black], [/color][color=Blue]N2400[/color][color=Black],[/color][color=Blue]([/color][color=Purple]b2[/color][color=Blue]) [/color][color=Green];You add a " " after b2..(b2," ")??  

;serout c.1,n2400,("Distance=",distance," kM ",metres," M")  you add this Tobie[/color]

[color=Blue]endif
goto [/color][color=Black]main[/color]
 
Last edited:

stan74

Senior Member
I think the speedometer on my bike measures the time between pulses and averages a few measurements then calculates speed from that. That's why it updates every 2 seconds and seems fairly accurate.
 

Tobie Calvert

New Member
Hello Stan,
I really appreciate all of the help you have kindly been giving me. I have used the code you kindly provided and altered all green hashtags to suit the need of my set criteria. However. I was wondering if you could help me with one more thing? The problem occurs when I run the code, the program correctly displays the "Distance in KM and M" but I still cannot get it to display any form of numbers. When I manipulate the proximity switch with the magnet, simulating a pulse, it comes up with all different letters and characters in the place on the OLED where the actual distance should be displayed. Linked below is some photos of what I'm trying to explain as well as my current code.
Once again, many thanks,
Tobie View attachment 20863
 

Attachments

stan74

Senior Member
dunno Tobie, I just copied code for my lcd. The rev ed lcd has the griff in the online manual. You use #metres not metres.
Combining Predefined Messages and Variables
It is often useful to combine predefined messages with variables e.g. displaying the
score of a game. The following program shows how to show the two scores from
two players, presuming message 1 and message 2 have been pre-programmed with
the phrases “Player 1=” and “Player 2=” (see above).
init: pause 500
main: serout B.7,N2400,(1)
pause 10
serout B.7,N2400,(254,137,#b1,” “)
serout B.7,N2400,(2)
pause 10
serout B.7,N2400,(254,201,#b2,” “)
let b1 = b1 + 1
let b2 = b2 + 2
pause 500
goto main
Note that the message code (1 or 2) is first output. A delay of 10ms is then added to
allow the LCD module to display the message. The cursor is the moved 9 positions
along the screen (to the position after the = sign by the 254,137 or 254,210
command) and then the variable value is displayed. Note that the # symbol tells the
microcontroller to output the ASCII equivalent of the variable value, not the direct
value (e.g. “6” “5” not the value 65, which would actually appear as the character
“A”!) Two additional spaces are then also added to ensure variable value changes
are overwritten correctly (e.g. to overwrite ‘234’ by ‘1’ you must output
‘1(space)(space)‘ to ensure the ‘34’ of the first number is overwritten by the spaces.)
 

stan74

Senior Member
Handy tip Tobie. Read the instructions...the last thing I do :) google "lcd display variables". I use subroutines for displaying numbers and text on my lcd not #variable: I found 1 listing that does everything for my 128x64 oled on google.
DisplayChar:
temp = abyte - " "
if temp< 8 then
if temp=0 then
writei2c(0x40, 0x00, 0x00, 0x00, 0x00, 0x00) ' space
elseif temp=1 then
writei2c(0x40, 0x00, 0x00, 0x5F, 0x00, 0x00) ' !
elseif temp=2 then
writei2c(0x40, 0x00, 0x07, 0x00, 0x07, 0x00) ' "
elseif temp=3 then
writei2c(0x40, 0x14, 0x7F, 0x14, 0x7F, 0x14) ' #
elseif temp=4 then
writei2c(0x40, 0x24, 0x2A, 0x7F, 0x2A, 0x12) ' $
elseif temp=5 then
writei2c(0x40, 0x23, 0x13, 0x08, 0x64, 0x62) ' %
elseif temp=6 then
writei2c(0x40, 0x36, 0x49, 0x56, 0x20, 0x50) ' &
elseif temp=7 then
writei2c(0x40, 0x00, 0x08, 0x07, 0x03, 0x00) ' '
endif
return
endif
temp = temp - 8
temp = temp * 5
b1 = temp + 4
for b0 = temp to b1
readtable b0, aByte
writeI2C(0x40,abyte)
next b0
return
DisplayNum:
' Words are always 5 chars long, but may be zero led.
b3 = 1
for b2 = 0 to 4
temp = 4-b2
aByte = DispNum DIG temp + "0"
if aByte="0" and b3=1 then
goto DisplayNumCont ' Don't show leading spaces
elseif abyte<>"0" and b3=1 then
b3=0
endif
GOSUB DisplayChar
DisplayNumCont:
next b2
return
 
Top