Remote Control Props:
JMLStamp2p
Posts: 259
Hello Paul,
I have narrowed my problem down somewhat. I have (2) attached "Spin" Files:
1) Sloss_Keypad_Input_3_08_Final····· 'Transmitter End
2) Sloss_Keypad_Input_3_08_Rx_Fix··· 'Receiver End
If I load my Transmitter and Receiver props with the associated code above. The Transmitter code for the transmitting Prop and the Receiver code for the receiver Prop I can send the numbers and everything works perfect every time, from the transmitter to the receiver.
I am trying to write one program that I can run in both props to transmit & recieve which is the ·( Sloss_Keypad_Input_3_08_Final )·file. It is actually a·combonation of the "2" files. I have the rxStr method written so that
if I press the "Star" button on my (4 by4) matrix Keypad it will go to the Receive_Loop Method and simulate the file that works every time, the "Sloss_Keypad_Input_3_08_Rx_Fix"·file. When I have the receive Prop go to this method and then transmit 3 sets of Three digit numbers from the transmitting end this is what happens. The Recieving end gets the 9 digits but does not increment the LCD cursor as it does when I run the "Sloss_Keypad_Input_3_08_Rx_Fix" alone in the recieve Prop. The First location in the LCD displays all the digits sent but "1" at a time in location Col-18, Row-2 on my LCD. For some reason I am having a real problem figuring out
what is causing this, I actually copied and pasted the exact code in the working file to the non working section of "Sloss_Keypad_Input_3_08_Final"·which is the "Receive_Loop" method.
I am putting a tremendous amount of time into·my study of·Spin as I can see
the potential of using the Prop as an "Instrumentation Processor" at·our plant. I appreciate all the help in the forum but have found that there are times you can do all the studying you possibly·can from the Prop manual, look at all the examples for "newbees" and still need the help of a seasoned programmer.·It's like a puzzle sometimes all the pieces start looking the same :>)
If You would be so kind as to help with this part of my project it would be greatly appreciated.
Sincerely,
John Logan
Sloss Industries
JMLStamp2p
<edit> took the Attn: from subject line.
Post Edited By Moderator (Paul Baker (Parallax)) : 3/22/2008 8:48:40 PM GMT
I have narrowed my problem down somewhat. I have (2) attached "Spin" Files:
1) Sloss_Keypad_Input_3_08_Final····· 'Transmitter End
2) Sloss_Keypad_Input_3_08_Rx_Fix··· 'Receiver End
If I load my Transmitter and Receiver props with the associated code above. The Transmitter code for the transmitting Prop and the Receiver code for the receiver Prop I can send the numbers and everything works perfect every time, from the transmitter to the receiver.
I am trying to write one program that I can run in both props to transmit & recieve which is the ·( Sloss_Keypad_Input_3_08_Final )·file. It is actually a·combonation of the "2" files. I have the rxStr method written so that
if I press the "Star" button on my (4 by4) matrix Keypad it will go to the Receive_Loop Method and simulate the file that works every time, the "Sloss_Keypad_Input_3_08_Rx_Fix"·file. When I have the receive Prop go to this method and then transmit 3 sets of Three digit numbers from the transmitting end this is what happens. The Recieving end gets the 9 digits but does not increment the LCD cursor as it does when I run the "Sloss_Keypad_Input_3_08_Rx_Fix" alone in the recieve Prop. The First location in the LCD displays all the digits sent but "1" at a time in location Col-18, Row-2 on my LCD. For some reason I am having a real problem figuring out
what is causing this, I actually copied and pasted the exact code in the working file to the non working section of "Sloss_Keypad_Input_3_08_Final"·which is the "Receive_Loop" method.
I am putting a tremendous amount of time into·my study of·Spin as I can see
the potential of using the Prop as an "Instrumentation Processor" at·our plant. I appreciate all the help in the forum but have found that there are times you can do all the studying you possibly·can from the Prop manual, look at all the examples for "newbees" and still need the help of a seasoned programmer.·It's like a puzzle sometimes all the pieces start looking the same :>)
If You would be so kind as to help with this part of my project it would be greatly appreciated.
Sincerely,
John Logan
Sloss Industries
JMLStamp2p
<edit> took the Attn: from subject line.
Post Edited By Moderator (Paul Baker (Parallax)) : 3/22/2008 8:48:40 PM GMT
Comments
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
I am 1010, so be surprised!
Forgive me if it came across that way, I have not had many people that were willing to respond to what I am trying to do. I will
check out the private e-mail. And if you like I would love for you to look at the code posted.
Regards,
JMLStamp2p
It is not possible to send attachements by PM...
I did not understand it the way that people should be excluded, but that this needs not immediate attention from deSilva (which generally makes me respire)
You have a recursive call of Receive_Loop calling itself and that will ultimately cause 'bad things' to happen.
I think this is one of those cases where you've strayed a little too far out of your depth and are trying to bash something into shape without having something which can be bashed into shape.
You have quite a complex configuration which is hard for you to debug and for anyone else to follow if they do not have the time to put into investigating all you've done and are trying to do. What I do in such cases is strip out everything which could be causing a problem and get back to the bare basics. In this case get inter-Propeller comms working without the complexity of scanning keypads, passing over multi-digit numbers and all the encoding and decoding used there. Have one send a known sequence of characters, say one a second and have the other put them on the LCD. Get that working then start moving the code forward to re-introduce sending multi-digit numbers, key-scanning and so on a step at a time.
Unless you've got good foundations the rest will always be wobbly and in danger of collapse.
I also find it invaluable to have some sort of debugging mechanism, either the TV_Text display or serial output to a terminal emulator, so I can put 'print statements' in the code to see where execution is going and check whether variables hold the values I expect or not. When it all goes wrong ( and it invariably does ), it's a sometimes long and arduous task of trying to determine what is happening compared to what should be happening and then having to determine why there is a difference to what was expected. It's usually the original programmer best equipped to do that as they most intimately understand what the code should be doing. Others can look at the code, spot obvious problems ( as above ), but most often it is down to the programmer themselves to do the necessary debugging.
on it every time, so thats a start. I understand about using the LCD as a debug tool and will try and incorperate it a little more than I've done.
Thanks for the advice,
JMLStamp2p
Narrowing the code down to where something is going wrong is key. Once you find a place where something is wrong, it then means working backwards to discover how that could be and ultimately what's causing that.
Some people seem to have a better disposition to debugging than others. I find it invaluable to step away from the problem and think about why something could be happening then come back and check to see how my theory matches with what is really happening.
-Phil
Post Edited (Phil Pilgrim (PhiPi)) : 3/9/2008 6:49:43 PM GMT
········ cognew(rxStr(9, @datain), @ rsStr_Stack)
·········cognew(Received_Data(9,@datain_2), @ RD_Stack
·······
·········data.stop
·········data.start((1,0,%0010,9600)
·········data_LCD.stop
·········data_LCD.start(3,2,0,19200)
·········LCD_Setup
·········repeat
············· rxStr(9, @datain)
··············Received_Data(9,@datain_2)
·········
·········
rxStr & Received_Data both make calls to FullDuplexSerial via the cogs started above. Both methods wait for
"9" numbers to be entered "rxStr via the Keypad and "Received_Data" via the tranceiver. After these "9" numbers are entered in let say the rsStr method I want it to loop inside itself so to speak and go back for another 9 numbers. I want it to do this·without interupting the Received_Data method that is doing the same thing at the same time. While doing this if either method receives "9" bytes then I want it to go to the "Print_Status_To_LCD method to display the numbers entered and then to the Transmit_Data method to transmit them to the remote Prop. After doing this I want it to return to the repeat loop, is their a problem doing this as long as I make sure that I have "return statments" at the end of each method called ?
JMLStamp2p
Note: Did not list
cognew(rxStr(9, @datain), @ rsStr_Stack)
cognew(Received_Data(9,@datain_2), @ RD_Stack)
data.stop
data.start((1,0,%0010,9600)
data_LCD.stop
data_LCD.start(3,2,0,19200)
LCD_Setup
repeat
rxStr(9, @datain)
Received_Data(9,@datain_2)
I have the following questions:
1)What precautions should I take when using arrays, other than the size and declaration ?
2)I believe that the "return" statement "Pops" data off the Stack that has been put there due
to a method call, is this correct ? And is there anything else that I should be aware of as far as seperate stacks for each cog ?
To answer your recent questions,
The code you posted won't work quite like you expect, At the start you call them into new cogs, the following code is immediately executed regardless what is going on in the two cogs. Then you go and call the two routines again, but this time you are calling one at a time, they execute in the current cog then the next one runs, but they do not run simultaneously. Typically the way you would program the subfunctions rxStr and Received_Data is to have them continue to run executiing thier code. If you have a situation where your top level program and subfunctions need to comminicate, you assign a memory location to serve as a sort of a mailbox to send messages. Coded this way, your main program's repeat loop would be empty. I haven't looked at the subfunctions, so I don't know if they are performing as you expect, but if not I can take a look at them.
Really the only thing you need to deal with arrays is the start address and the number of elements.
A spin routine's return value is on the stack and is returned when called for.
PS, if you want to edit a post, just click on the pencil icon of the post.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Paul Baker
Propeller Applications Engineer
Parallax, Inc.
What I am not clear on is how to make Recieved_Data and rxStr run at the same time both looping independantly of each other.
Is it as simple as having a nested repeat loop in each method? I understanding that starting new Cogs causes them to run in Parallel but as soon as either one has received "9" digits it is going back to main and halting, is it not ? I could really use an example of this code. I believe that I can handle the other methods if I can just get this in my Head :>)
JMLStamp2p
John.
First you need to remove this from main
Than you need to make sure that rxStr and Received_Data not return. If you have a return in them than the new cogs will run through for 9 digits and then stop. In pseudo code this is what you want to do
So 90% is done.
By the way, it is a good idea to develop pseudo code like this before you start programming. It will help you and it will help others find problems quicker if you post it along with your actual code.
posted the working method below. I will have to add a line at the botton to
clear the array before looping back which I plan to go over the it more tonight.
It is running in its own Cog and looping as it should to get 9 digits. It resets
the LCD and gets 9 more digits,ect. Tommorow I will make sure everything is
correctly and will then add the Received_Data method to run its its own Cog.
Thank You !!! Your help is Greatly appreciated ...
JMLStamp2p
PUB RxStr(Num_of_Chars,strPtr) : char
·repeat
·· char := data_LCD.rx
·· if Num_of_Chars == 9
····· data_LCD.tx(254)·····································
····· data_LCD.tx(71)··············
····· data_LCD.tx(5)
····· data_LCD.tx(2)
··
·· elseif Num_of_Chars == 8
········ data_LCD.tx(254)·····································
········ data_LCD.tx(71)··············
········ data_LCD.tx(6)
········ data_LCD.tx(2)
··
·· elseif Num_of_Chars == 7
········ data_LCD.tx(254)·····································
········ data_LCD.tx(71)··············
········ data_LCD.tx(7)
········ data_LCD.tx(2)
·· elseif Num_of_Chars == 6
········ data_LCD.tx(254)·····································
········ data_LCD.tx(71)··············
········ data_LCD.tx(5)
········ data_LCD.tx(3)
··
·· elseif Num_of_Chars == 5
········ data_LCD.tx(254)·····································
········ data_LCD.tx(71)··············
········ data_LCD.tx(6)
········ data_LCD.tx(3)··
·· elseif Num_of_Chars == 4
········ data_LCD.tx(254)·····································
········ data_LCD.tx(71)··············
········ data_LCD.tx(7)
········ data_LCD.tx(3)··
·· elseif Num_of_Chars == 3
········ data_LCD.tx(254)·····································
········ data_LCD.tx(71)··············
········ data_LCD.tx(5)
········ data_LCD.tx(4)
··
·· elseif Num_of_Chars == 2
········ data_LCD.tx(254)·····································
········ data_LCD.tx(71)··············
········ data_LCD.tx(6)
········ data_LCD.tx(4)··
·· elseif Num_of_Chars == 1
········ data_LCD.tx(254)·····································
········ data_LCD.tx(71)··············
········ data_LCD.tx(7)
········ data_LCD.tx(4)
········
· '
·· elseif Num_of_Chars == 0··
····· 'byte[noparse][[/noparse] strPtr] := 0
·····
····· data_LCD.tx(254)
····· data_LCD.tx(84)
· 'Turn Blinking Cursor off.
·· if char == (88)········
····· char := 1···········
····· data_LCD.dec(char)··
··························
·· if char == (83)···········
····· char := 2································
····· data_LCD.dec(char)··
·· if char == (78)············
····· char := 3·································
····· data_LCD.dec(char)
·· if char == (87)·······························································
····· char := 4·································
····· data_LCD.dec(char)
·····
·· if char == (82)······························································
····· char := 5·································
····· data_LCD.dec(char)
·· if char == (77)·······························································
····· char := 6·································
····· data_LCD.dec(char)
·· if char == (86)·······························································
····· char := 7·································
····· data_LCD.dec(char)
·· if char == (81)·······························································
····· char := 8·································
····· data_LCD.dec(char)
·····
·· if char == (76)·······························································
····· char := 9·································
····· data_LCD.dec(char)
·· if char == (80)·······························································
····· char := 0·································
····· data_LCD.dec(char)·····
·· if char == (73)·······························································
····· 'char := "A"·······························
····· data_LCD.tx(char)···········
····· data_LCD.tx(254)·····················
····· data_LCD.tx(88)··
·· if char == (72)·······························································
····· 'char := "B"·······························
····· data_LCD.tx(char)···········
····· data_LCD.tx(254)·····················
····· data_LCD.tx(88)
·····
·· if char == (71)·······························································
····· 'char := "C"·······························
····· data_LCD.tx(char)···········
····· data_LCD.tx(254)·····················
····· data_LCD.tx(88)
····
·· if char == (70)·······························································
····· 'char := "D"··
·· if char == (70)·············
····· data_LCD.tx(254)···················
····· data_LCD.tx(88)
·····
·· byte[noparse][[/noparse]strPtr++] := char
· 'Save byte & increment array pointer.
··
·· if Num_of_chars -- == 1
··· 'Have we received 9 Digits ? if not loop back.
··· 'If we have received 9 digits execute indented code.·······
·····························
····· Print_Status_To_LCD(@rxStr_array)················
····· Transmit_Timer_values(@rxStr_array)
····· byte[noparse][[/noparse]strPtr]:= 0
····· LCD_Setup
····· Num_of_Chars := 9····
·····
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Paul Baker
Propeller Applications Engineer
Parallax, Inc.
appears to be in every if statement in the first part of your program. Why not just do it at the beginning and you will save some space in the hub.
i have a question to understand your RxStr-method right
as soon as a byte is received by
char := data_LCD.rx
you send a byte to the LCD
by
if char == (88)
char := 1
data_LCD.dec(char)
etc.
and if you have received 9 digits
you call the methods
Print_Status_To_LCD(@rxStr_array)
Transmit_Timer_values(@rxStr_array)
what's the difference between the single bytes sended to the lcd by
if char == (88)
char := 1
data_LCD.dec(char)
etc.
and the method
Print_Status_To_LCD(@rxStr_array) ?
Do you have a LCD with 2 rows ?
one row showing the Input from the keypad and the other showing the actual received serial data?
regards
Stefan
what's the difference between the single bytes sent to the lcd by
if char == (88)
char := 1
data_LCD.dec(char)
etc.
This is setting the local varible "char" to the dec. value "1" of course. My LCD
outputs "88" when I press the digit "1" so I am converting it to "1" to correspond to
the digit that I pressed. The LCD is a 4 by 20 by Matrix Orbital, has programmable
outputs, a direct keypad interface and debouncing built in, Parallax sell it.
I have a question: My rxStr method is running fine but when I transmit out the 2nd
set of numbers to the LCD, the recieving end shows the last set that I had sent.
If I press the reset button on my transmitting end where our rxStr method is
running and transmit 9 more digits the updtated set of numbers show on the
receiving end. It looks like my array is not being cleared·in my rxStr method.
Here is the code: I am trying to use bytefill to clear the array and byte[noparse][[/noparse]strPtr]:= 0
to reset the array pointer back to location "0" but still having the problem,
What am I missing?
·if Num_of_chars -- == 1
··· 'Have we received 9 Digits ? if not loop back.
··· 'If we have received 9 digits execute indented code.·······
·····························
····· Print_Status_To_LCD(@rxStr_array)················
····· Transmit_Timer_values(@rxStr_array)
····· byte[noparse][[/noparse]strPtr]:= 0
····· bytefill(@rxStr_array,0,9)
····· LCD_Setup
····· Num_of_Chars := 9
Regards,
JMLStamp2p
only makes the last element in the array 0!
So here is what you need to do. Don't change strPtr anywhere in the method. Leave it the same so that we always know where the array starts. Also, it would be a good idea to do the same thing with Num_of_Chars. Than you will need a local variable named something like count. When you write a byte to the array simple do this
Than you just need to check what count is compared to Num_of_Chars and reset count to 0 to start at the beginning of the array again. You will also need to make count 0 at the start of the method as it may not be initialised to zero.
byte strPtr[noparse][[/noparse]0] :=0
byte strPtr :=0
byte strPtr :=0
byte strPtr :=0
ect.
I have tried: bytefill(@strPtr,0,9) but it doesn't work either.
JMLStamp2p
The forum ate some of you array indexes so here they are again.
strPtr is a long on the stack that contains a pointer to the start of an array. You could do that but you will need the brackets around 'strPtr' like in my last post. However, it will be quicker to do bytefill(strPtr,0,9), but, this will only work if strPtr is the start of the array and you don't change it.
I presume that you have used the stamps from your name. Do the stamps have pointers or not or have you used them before? If not than I will try to explain a little about them.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Paul Baker
Propeller Applications Engineer
Parallax, Inc.
if Num_of_chars -- == 1
'Have we received 9 Digits ? if not loop back.
'If we have received 9 digits execute indented code.
Print_Status_To_LCD(@rxStr_array)
Transmit_Timer_values(@rxStr_array)
LCD_Setup
data.rxflush
data_LCD.rxflush
byte[noparse][[/noparse] strPtr]:= 0 'Are you saying that this should be: "long[noparse][[/noparse] strPtr]:= 0"
bytefill(@rxStr_array,0,9)
RxStr(9,@rxStr_array) 'Calling the method again.
I was thinking that after "bytefill(@rxStr_array,0,9)" the program would go back to "char := data_LCD.rx" get
more bytes and write over the array contents even if they were not cleared. I need some help understand the
pass by ref. thing I guess.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Paul Baker
Propeller Applications Engineer
Parallax, Inc.
In programming there is a thing called recursion. Recursion simply means that a method calls itself. For example
In theory, if you call doSomething it will call itself with x and y switched, and then call itself again, and again and again......
However, this won't actually happen. In the propeller (actually most computers) there is an area of memory that is called the stack. A stack is useful for all kinds of things like storing local variables, return values and various other things. The stack works kind of like a stack of paper on your desk. You can push things onto it (like putting a piece of paper on your deck) or pop things off it (like getting the top piece of paper off the stack on your deck). Now, every time you call a method in spin, the interpreter puts (pushes) several things on the stack. Some of these are used by the spin interpreter so that it knows where to come back to when it is finished the method (I think that there are 3 longs but I'm not sure). It also puts space for every argument that the method has, the return value and any local variables.
So, every time that we call the doSomething method above we are pushing 3 longs for the interpreter+1 long for the return value+2 arguments. This comes to a total of 6 longs every time we call this method! Now, to go back to the paper on you desk analogy, what will happen if you put things onto your desk and never take them off? Of course the pile of papers will get so high that you will not be able to put more on or the stack will fall over. The same thing is happening in this example. We are pushing 6 longs onto the stack every time we call doSomething, we are never taking anything off and we go into a loop that we can't get out of. So eventually you will use up all the RAM in your propeller. Once you have used up all the RAM your propeller will go back to the start of the RAM and write over some important settings.
So what can we do and is recursion still useful?
Consider this code
Now, this code is slightly different. It has a return in it. This means that if the condition x=0 is ever true than we will stop calling foo. We know this will eventually happen because every time we call foo we are calling it with 1 less than before. So if we called foo with x=3 what would happen? The table below shows the stack size and the value of x
x Stack size
3 5
2 10
1 15
0 20
But now x=0 so we don't call foo anymore. This is exactly what we want. The stack will have a maximum size of 20 and then start shrinking as all the methods return. And yes, this is useful for many things although I haven't shown an example that does anything useful.
Well, that was a lot more than I meant to type and I haven't really answered any of your questions yet. So
What you are doing in your post above is the basically the same as doSomething above. You call RxStr over and over, constantly pushing data onto the stack but never taking any off. Eventually you will run out of memory and bad things will happen to your program because you are writing data over the top of something else or the ROM.
I'll talk a bit about pointers and passing by reference in my next post and hopefully I can make it shorter than this one
The complete working code is attached via file, It is working just exactly like I want it to.
The keypads and tranceivers are running in their own Cogs and two seperate serial ports
are set up at diggerent baud rates. I had to call the Received_Data·AND rXStr methods
inside themselves for it to work so please give me your opinion as far as memory goes. I don't
want to be eating it up and have problems later on. Thank You so much for all the help you are giving me.
JMLStamp2p