Hey the main application uses the processor which uses the sensor, for formatting it uses DisplayFormat. I made objects of these and want to display a simple println but it doesn't print to the jide message window. What is wrong here?
Classes are looking much better now.
Change the method formatSpeed to · public StringBuffer formatSpeed(int x){ ··· a=0; ··· a = Format.bprintf(textSpeed,a,"%0d.",x/10); ··· a = Format.bprintf(textSpeed,a,"%d",x%10); ··· textSpeed[noparse][[/noparse]a]=0; ··· Format.printf("debug: %s\n",textSpeed); //debug textSpeed ··· b=0; ··· while (textSpeed[noparse][[/noparse]b]!=0){ ····· string.append(textSpeed[noparse][[/noparse]b]); ····· b++; ··· } ··· return string; · }
and see if the debug does get printed, it should.
Why do you keep converting asciiz strings to StringBuffer and then to String?
The Format class can print asciiz strings directly. No need for all these
conversions.
In the jide message window, make sure the enable option is on!
I have no javelin connected right now.
Are you sure the jide message window Enabled is on?
If it is not, nothing gets printed to the jide message window.
Add a welcome message to the start of main.
Format.printf("ApplicationFCv1\n");
Does that get printed?
I spotted the error.
You define a new processor in main().
The processor constructor defines a new sensor.
The sensor constructor calls run().
run() contains a while true loop that never exits.
So, code execution never continues back to main().
You should make the innerloop of that while true loop
a seperate method.
Then call that method from your main while true loop.
(The sensor constructor then must not call run())
Ah i see, yes i also thought about making objects of sensor and processor in application, but didn't know how exactly to do it. I see what you mean now, this works fine! I comprehend this code completely know.
Now that you understand how to use objects properly,
take a look at your DisplayFormat class. In my opinion
the Processor needs not to be known to the display class.
Instead of calling a Processor method from
the display class, pass the values to print via the
methods formatAverage and formatDistance,
just as you did with formatSpeed.
Then you don't need to pass the Processor object to the display
class.
Coming back on the code, tested it. Got much IDE error's. I have a question, why can't the sensor not have loop forever for pulses and the application do things at the same time. Isn't that called multitasking?
The javelin is not a real multitasking device. It only provides
background tasks (the VP's). No threads. So, to mimic
multitasking you should implement state machines for
several tasks.
A state machine maintains its state, and is frequently called
from the mainloop. Specific·events (for example a pin input state change)
change the state machine its state. The trick is never to wait for any
event to happen, rather introduce a wait·state from which is
immediately returned if the event has not happened.
int state;
int timePassed;
public boolean getPulse() { · switch (state) { ··· case 0: //wait for senPin to be high ·············· if (CPU.readPin(senPin)) state++; ·············· return false; ··· case 1: //wait for senPin to be low ·············· if (!CPU.readPin(senPin)) { ················ t.mark(); ················ state++; ···············} ·············· return false; ··· case 2: //wait for senPin to be high, then store pulse width ·············· if (CPU.readPin(senPin)) { ················ timePassed = t.passedMS(); ················ state=0; ·················return true; ···············} ·············· return false; ··· default: state=0; ·············· return false; · }
}
The idea is to call getPulse() from the mainloop and when it returns true,
you retrieve the·last timePassed, from which you can calculate speed.
As you can see, the·state machine equals the code you had for reading a pulse,
but it is split into small fragments called states. Note that the code never
waits. This allows you to execute other code from the mainloop while
no event has happened.
regards peter
Post Edited (Peter Verkaik) : 6/2/2006 8:26:59 PM GMT
I created an ApplicationFCv2 that implements the statemachine approach.
All·files in package fietsv2
Note that Processor class is no longer needed.
The calculateDistance and calculateAverage are now in the application class.
The Clock class maintains the realtime clock.
regards peter
Post Edited (Peter Verkaik) : 6/3/2006 12:13:43 PM GMT
I figured that would be a possible effect using the statemachine approach.
The problem is the sensor signal has a small high period and a large low period.
I adapted the sensor update() method to wait for the high period, and while it is high,
the update() does not return to the mainloop. Since the high period is small, this
should have no impact on the program behaviour, but does allow to detect
the start of the low period.
It got worse, the LED starts to burn when the program starts, and the sensor readings are worse. When a pulse·come by the·LED goes off, pulse comes by LED goes on. And so on..
That is correct. See the update() in Sensor.java
The led toggles with every pulse detected. I think that·is more clear
than having the led on only when the sensor signal is high due to
the small time the sensor signal is high. With toggling, at constant speed the led
on time and off time are equal (at least it is supposed to be, if it isn't
it indicates pulses are missed).
Another thing, your calculateDistance() method uses the pulsecount to
calculate distance. That method uses the calculation ····· dstm = UnsignedIntMath.umulf(circumference,1500);
The umulf() calculates circumference * (1500/65536), and since
circumference = 2 that always results in 0.
The right calculation for distance using pulses is · distance += circumference * pulsecount
where circumference = 20 (20 equals twenty 0.1m units or 2.0m)
For every pulse, add 20 to the distance.
That only works if no pulses are missed.
Could you post the ide message window output you get?
ApplicationFCv2
Sp = 000.00 km/h
D1 = 0.00 km
D2 = 0.00 km
Sp = 008.19 km/h
D1 = 0.00 km
D2 = 0.01 km
Sp = 009.76 km/h
D1 = 0.00 km
D2 = 0.01 km
Sp = 007.09 km/h
D1 = 0.00 km
D2 = 0.02 km
Sp = 008.44 km/h
D1 = 0.00 km
D2 = 0.03 km
Sp = 009.09 km/h
D1 = 0.00 km
D2 = 0.03 km
Sp = 015.41 km/h
D1 = 0.00 km
D2 = 0.04 km
Sp = 014.57 km/h
D1 = 0.00 km
D2 = 0.05 km
Sp = 024.08 km/h
D1 = 0.00 km
D2 = 0.07 km
Sp = 020.81 km/h
D1 = 0.00 km
D2 = 0.09 km
Sp = 020.81 km/h
D1 = 0.00 km
D2 = 0.10 km
Sp = 024.16 km/h
D1 = 0.00 km
D2 = 0.12 km
Sp = 031.72 km/h
D1 = 0.00 km
D2 = 0.14 km
Sp = 061.53 km/h
D1 = 0.00 km
D2 = 0.18 km
Sp = 053.33 km/h
D1 = 0.00 km
D2 = 0.21 km
Sp = 015.75 km/h
D1 = 0.00 km
D2 = 0.24 km
Sp = 007.94 km/h
D1 = 0.00 km
D2 = 0.25 km
I have put a sensor timing diagram in sensor.java
From this diagram it is clear the minimal pulsetime for
the sensor is 20 msec.
I added a poll() method in Sensor.java that returns the current speed.
Could you post the ide message window output for this adaptation?
regards peter
Post Edited (Peter Verkaik) : 6/5/2006 12:50:53 AM GMT
The clock of the bike is not an actual clock but gives the time that the bike was cycling. (rittijd)
How can i implement that in this way? Because my way doesn't seem to work (the passed time adding, you know what i did)
Johnny,
The realtime clock always starts at 0, and so it is your traveltime.
There are two ways to keep the time:
1. to add the passed time between pulses
2. to add time in small chunks using a timer loop
The 2nd makes the timekeeping independant from your· sensor pulses
and does take into account the time used by other code.
The clock class uses the 2nd approach.
Note that the clock timer is only marked just before the mainloop.
It is easy to·add a startstop button to stop/start the clock
(making it a stopwatch), so it would only count while cycling.
This startstop button could be virtual: stop the clock if no pulses
are received (eg. the bike stopped), start the clock when
pulses are received.
I added a startstop() and reset() to the clock class.
The clock initalizes to stop. So startstop() must be called at
the start of main.
The start must begin with the first pulse not at the beginning of the main because the bike computer will not count until you cycle. But this will mean that the main must be programmed different than just adding startstop?
Because it is now a state machine must the start and stop of the clock not be controlled from the sensor because there are the state?
The mainloop controls the clock by checking wether the bike moves
(speed > 0) or is stopped (speed =0).
I added a seperate start() and stop() to make it easier.
Note that poll() in Sensor is not a statemachine but poll() waits
for two consecutive high pulses, the time between those 2 high pulses
determines the speed. (speed=circumference/time)
You can simply test for a low input pin
to change mode: · if (!CPU.readPin(modePin)) { ··· mode = (mode+1)%3; //support for 3 modes · }
For wheel circumference you best have a number of standard
wheel circumferences (26" and 28" are two standard values)
Then you can use · if (!CPU.readPin(parameterPin)) { ··· circumferenceIndex = (circumferenceIndex+1)%2; //support for 2 wheel sizes ··· circumference = circumferenceArray[noparse][[/noparse]circumferenceIndex]; ··· sen.setCircumference(circumference); · }
static final·int[noparse]/noparse circumferenceArray = {20,24};
Put the 2 button test simply before clock update in mainloop.
The remaining code·takes enough time so debouncing is not required.
You must add a method setCircumference to the Sensor class.
I've tried the following code that I created to initialise the circumference.
while (true) {
if (!CPU.readPin(bt1Pin)){
circumferenceIndex = (circumferenceIndex+1)%9; //support for 9 wheel sizes
circumference = circumferenceArray[noparse][[/noparse]circumferenceIndex];
}
if (!CPU.readPin(bt2Pin)){
break;
}
}
This is the result: I push button 2 the program starts, I push button 1 and also the program starts and the buttons are not on the same pin I checked that.
You have put a pullup resistor on each pin?
A value of 10k or 4k7 will do.
Without the resistors there may be noise
at pin2 which leads to starting the program.
while (true) { · if (!CPU.readPin(bt1Pin)){ ··· circumferenceIndex = (circumferenceIndex+1)%9; //support for 9 wheel sizes ··· circumference = circumferenceArray[noparse][[/noparse]circumferenceIndex]; ··· System.out.println(circumference); ··· if (!CPU.readPin(bt2Pin)) { ····· System.out.println("pin2 is low"); ··· } ··· CPU.delay(10500); //wait 1 second · } · if (!CPU.readPin(bt2Pin)){ ··· break; · }
}
While you keep bt1pin pressed, you should see a new circumference displayed every second.
If you never press bt2pin, the while loop should never exit. If you press bt1pin, the status
of bt2pin is displayed if it is also low, which shouldn't be. If it is there is some
wiring problem.
this has no effect still doing the same thing! I can't figure out what the problem is, It's not the wiring I think. I didn't even show the system.out.println.
Comments
Change the method formatSpeed to
· public StringBuffer formatSpeed(int x){
··· a=0;
··· a = Format.bprintf(textSpeed,a,"%0d.",x/10);
··· a = Format.bprintf(textSpeed,a,"%d",x%10);
··· textSpeed[noparse][[/noparse]a]=0;
··· Format.printf("debug: %s\n",textSpeed); //debug textSpeed
··· b=0;
··· while (textSpeed[noparse][[/noparse]b]!=0){
····· string.append(textSpeed[noparse][[/noparse]b]);
····· b++;
··· }
··· return string;
· }
and see if the debug does get printed, it should.
Why do you keep converting asciiz strings to StringBuffer and then to String?
The Format class can print asciiz strings directly. No need for all these
conversions.
In the jide message window, make sure the enable option is on!
regards peter
It should be
· public static void main() {
··· proc = new Processor(15);
··· t = new Timer();
··· df = new DisplayFormat();
··· while (true) {
····· proc.calculateSpeed();
····· t.mark();
····· if (t.timeoutSec(3)){
······· b = true;
····· }
····· while (b == true){
······· a1 = df.formatSpeed(proc.getSpeed());
······· a2 = a1.toString();
······· System.out.println(a2);
······· b=false;
····· }
··· }
· }
otherwise b=false and main() ends.
You can simplify main to
· public static void main() {
··· proc = new Processor(15);
··· t = new Timer();
··· df = new DisplayFormat();
··· while (true) {
····· proc.calculateSpeed();
····· a1 = df.formatSpeed(proc.getSpeed());
····· a2 = a1.toString();
····· System.out.println(a2);
····· t.mark();
····· while·(!t.timeoutSec(3)) ; //wait for 3 sec
··· }
· }
regards peter
Johnny
Are you sure the jide message window Enabled is on?
If it is not, nothing gets printed to the jide message window.
Add a welcome message to the start of main.
Format.printf("ApplicationFCv1\n");
Does that get printed?
regards peter
You define a new processor in main().
The processor constructor defines a new sensor.
The sensor constructor calls run().
run() contains a while true loop that never exits.
So, code execution never continues back to main().
You should make the innerloop of that while true loop
a seperate method.
Then call that method from your main while true loop.
(The sensor constructor then must not call run())
regards peter
Johnny
to your application class.
The required objects for classes are passed via constructors.
Note how your mainloop now shows exactly your program flow.
regards peter
Thanks for your help peter!
Johnny
take a look at your DisplayFormat class. In my opinion
the Processor needs not to be known to the display class.
Instead of calling a Processor method from
the display class, pass the values to print via the
methods formatAverage and formatDistance,
just as you did with formatSpeed.
Then you don't need to pass the Processor object to the display
class.
regards peter
·
Johnny
P.S. i will get back on the other classes later
background tasks (the VP's). No threads. So, to mimic
multitasking you should implement state machines for
several tasks.
A state machine maintains its state, and is frequently called
from the mainloop. Specific·events (for example a pin input state change)
change the state machine its state. The trick is never to wait for any
event to happen, rather introduce a wait·state from which is
immediately returned if the event has not happened.
int state;
int timePassed;
public boolean getPulse() {
· switch (state) {
··· case 0: //wait for senPin to be high
·············· if (CPU.readPin(senPin)) state++;
·············· return false;
··· case 1: //wait for senPin to be low
·············· if (!CPU.readPin(senPin)) {
················ t.mark();
················ state++;
···············}
·············· return false;
··· case 2: //wait for senPin to be high, then store pulse width
·············· if (CPU.readPin(senPin)) {
················ timePassed = t.passedMS();
················ state=0;
·················return true;
···············}
·············· return false;
··· default: state=0;
·············· return false;
· }
}
The idea is to call getPulse() from the mainloop and when it returns true,
you retrieve the·last timePassed, from which you can calculate speed.
As you can see, the·state machine equals the code you had for reading a pulse,
but it is split into small fragments called states. Note that the code never
waits. This allows you to execute other code from the mainloop while
no event has happened.
regards peter
Post Edited (Peter Verkaik) : 6/2/2006 8:26:59 PM GMT
All·files in package fietsv2
Note that Processor class is no longer needed.
The calculateDistance and calculateAverage are now in the application class.
The Clock class maintains the realtime clock.
regards peter
Post Edited (Peter Verkaik) : 6/3/2006 12:13:43 PM GMT
I've run a quick test on on my javelin stamp with this code.
When the magnet runs by the hall sensor it somethimes leaves the LED burning till the magnet comes again.
Also it can not keep up at higher speeds.
Also after few pulses it generates an Out of bounds exception.
Johnny
The problem is the sensor signal has a small high period and a large low period.
I adapted the sensor update() method to wait for the high period, and while it is high,
the update() does not return to the mainloop. Since the high period is small, this
should have no impact on the program behaviour, but does allow to detect
the start of the low period.
Please post the results using this adaptation.
regards peter
Johnny
The led toggles with every pulse detected. I think that·is more clear
than having the led on only when the sensor signal is high due to
the small time the sensor signal is high. With toggling, at constant speed the led
on time and off time are equal (at least it is supposed to be, if it isn't
it indicates pulses are missed).
Another thing, your calculateDistance() method uses the pulsecount to
calculate distance. That method uses the calculation
····· dstm = UnsignedIntMath.umulf(circumference,1500);
The umulf() calculates circumference * (1500/65536), and since
circumference = 2 that always results in 0.
The right calculation for distance using pulses is
· distance += circumference * pulsecount
where circumference = 20 (20 equals twenty 0.1m units or 2.0m)
For every pulse, add 20 to the distance.
That only works if no pulses are missed.
Could you post the ide message window output you get?
regards peter
From this diagram it is clear the minimal pulsetime for
the sensor is 20 msec.
I added a poll() method in Sensor.java that returns the current speed.
Could you post the ide message window output for this adaptation?
regards peter
Post Edited (Peter Verkaik) : 6/5/2006 12:50:53 AM GMT
The clock of the bike is not an actual clock but gives the time that the bike was cycling. (rittijd)
How can i implement that in this way? Because my way doesn't seem to work (the passed time adding, you know what i did)
Thanks Johnny
The realtime clock always starts at 0, and so it is your traveltime.
There are two ways to keep the time:
1. to add the passed time between pulses
2. to add time in small chunks using a timer loop
The 2nd makes the timekeeping independant from your· sensor pulses
and does take into account the time used by other code.
The clock class uses the 2nd approach.
Note that the clock timer is only marked just before the mainloop.
It is easy to·add a startstop button to stop/start the clock
(making it a stopwatch), so it would only count while cycling.
This startstop button could be virtual: stop the clock if no pulses
are received (eg. the bike stopped), start the clock when
pulses are received.
I added a startstop() and reset() to the clock class.
The clock initalizes to stop. So startstop() must be called at
the start of main.
regards peter
Because it is now a state machine must the start and stop of the clock not be controlled from the sensor because there are the state?
Johnny
(speed > 0) or is stopped (speed =0).
I added a seperate start() and stop() to make it easier.
Note that poll() in Sensor is not a statemachine but poll() waits
for two consecutive high pulses, the time between those 2 high pulses
determines the speed. (speed=circumference/time)
regards peter
Thanks for the help. It works fine now. I can work further on putting this al together with the lcd codes andso on.
If i also want to add class button to it, to input circumference and switch between display? where must i begin with that?
Johnny
to change mode:
· if (!CPU.readPin(modePin)) {
··· mode = (mode+1)%3; //support for 3 modes
· }
For wheel circumference you best have a number of standard
wheel circumferences (26" and 28" are two standard values)
Then you can use
· if (!CPU.readPin(parameterPin)) {
··· circumferenceIndex = (circumferenceIndex+1)%2; //support for 2 wheel sizes
··· circumference = circumferenceArray[noparse][[/noparse]circumferenceIndex];
··· sen.setCircumference(circumference);
· }
static final·int[noparse]/noparse circumferenceArray = {20,24};
Put the 2 button test simply before clock update in mainloop.
The remaining code·takes enough time so debouncing is not required.
You must add a method setCircumference to the Sensor class.
regards peter
I've tried the following code that I created to initialise the circumference.
while (true) {
if (!CPU.readPin(bt1Pin)){
circumferenceIndex = (circumferenceIndex+1)%9; //support for 9 wheel sizes
circumference = circumferenceArray[noparse][[/noparse]circumferenceIndex];
}
if (!CPU.readPin(bt2Pin)){
break;
}
}
This is the result: I push button 2 the program starts, I push button 1 and also the program starts and the buttons are not on the same pin I checked that.
Thanks Johnny
A value of 10k or 4k7 will do.
Without the resistors there may be noise
at pin2 which leads to starting the program.
regards peter
while (true) {
· if (!CPU.readPin(bt1Pin)){
··· circumferenceIndex = (circumferenceIndex+1)%9; //support for 9 wheel sizes
··· circumference = circumferenceArray[noparse][[/noparse]circumferenceIndex];
··· System.out.println(circumference);
··· if (!CPU.readPin(bt2Pin)) {
····· System.out.println("pin2 is low");
··· }
··· CPU.delay(10500); //wait 1 second
· }
· if (!CPU.readPin(bt2Pin)){
··· break;
· }
}
While you keep bt1pin pressed, you should see a new circumference displayed every second.
If you never press bt2pin, the while loop should never exit. If you press bt1pin, the status
of bt2pin is displayed if it is also low, which shouldn't be. If it is there is some
wiring problem.
regards peter
Johnny
regards peter