stevenmess,
I posted the above before I read the information about how the stack works which was very informable, Thank You. Please take a look at the file that I attached above and give me your opinion and suggestions. I am going to go back and read the above post and make sure that I understand it completely.
JMLStamp2p
inside the method RxStr you are calling RxStr recursive when key "D" is pressed
this will eat up memory over time
it is the same with the method Recieved_Data
inside if Num_of_nums-- == 1
the method RxStr runs in cogNr 2
and uses the method Print_Status_to_LCD which is sending data (using data_LCD.tx() )
to the LCD connected on PINs 2,3
your method Recieved_Data is running in CogNr 1
and uses the method Print_Status_To_LCD_Reciever (using data_LCD.tx TOO !)
to the LCD connected on PINs 2,3
this means:
two cogs that are running independent from each other but they are using the
same serial connection !!
The logic state of output-pins are "ored" inside the propellerchip
So if both methods use data_LCD.tx at the same time the logic state of PIN 2 and 3
will switch high and low UNDEFINED because of mixing the serial bitstreams of the two calls of data_LCD.tx() !!
here you have to change to a - what i call - shared bufferarray with a lock-mechanism (sometimes called "semaphore")
now a solution to thi sproblem could be:
write a method that does ONLY READ from the bufferarray and is the ONLY ONE to send data to the LCD
this method should be called endlessly from ONE place by a repeat-loop
repeat
Send_Buffered_Data_to_LCD
The methods RxStr and Recieved_Data have to check if a Flag-variable is set to status "unlocked"
BEFORE they start WRITING into the bufferarray
if the status is "locked" then they just wait for status "unlocked" or the just exit without writing to the bufferarray
if status is "unlocked" they set the status themselve to "locked"
and AFTER that they start writing to the bufferarray
after FINISHING writing the status is set to "unlocked"
by this mechanism you avoid that both methods write to the bufferarray at THE SAME time
writing at the same time would mix up the data of the two calls
without the lock-mechanism mixing up the data could happen at ANY time beoause the methods RxStr and Recieved_Data are running
in different cogs
best regards
Stefan
Post Edited (StefanL38) : 3/13/2008 5:05:30 PM GMT
StefanL38,
Thank you for your post, this is a little over my head so I might need some example code to help me get through it. I will definately start studying what you and stevenmess have posted. I was thinking about "Locking out" rxStr when data is being handled by the receiver
and vise versa anyway just as a precaution. It is unlikely that both will be writing to the LCD at the same time due to the nature of how our plant works but sometimes what can go wrong will :>( I tell ya, I am so darn excited about just being able to send and receive at this point I 'm afraid to touch the thing :>) I have been spending a tremendous amount of
time trying to get up to speed with the Propeller.
Thanks for your help guys,
JMLStamp2p
stevenmess & StefanL38,
The only thing that the data entering the keypad and tranceiver are really doing "or what I want them to do" is transfer their value to the Global varibles TValue_1, TValue_2 & TValue_3. After this transfer of data takes place in my code could I just "pop" the data off the stacks since I wont really be using any previous return values after the data is sent to the LCD ? So after every "9" bytes are received via either Method both stacks are cleared and the Gloal varibles "updated" every time another "9" bytes are recieved.
JMLStamp2p
Also, After each Cog is stoped arn't the stacks cleared ? If so at the end of rxStr could I simply stop and restart the cog before it looped back to receive another "9" bytes ? I realize this is probally not the best way to handle this but just trying to make sure I understand what each command is doing.
JMLStamp2p
StefanL38,
I re-read your post above and it made perfect sense, the "locks" sound like it is very useful. I am still a little cloudy on the best way to Clear my Stacks. Can I use something like: longfill(@rxStr_Stack,0,20) to clear the stack and then reset the pointer if nessessary. And then do the same thing for my Received_Data Method ?
JMLStamp2p
Sorry this took so long. Work, tafe, the Aussie meeting on irc and sleeping got in the way
Now for pointers.
As discussed in my previous post, one of the things that the stack is used for is passing parameters of methods. When you do something like this
doSomething(2,3)
The spin interpreter first stores where to come back to on the stack and then pushs the arguments (2 and 3 in this case) onto the stack. This is called passing by value in some programming languages. So the value you put in parenthesis are copied onto the stack. This means that you can do whatever you want to them without affecting the original value. This can be really handy. For example
VAR
byte aVar
PUB main
repeat aVar from 5 to 1
far(aVar)
PUB far(x)
repeat while x>0
serial.dec(x--)
This changes the value of x but it will not affect the value of aVar (it would mess up the loop in main if it did change aVar). This is all very good but what if we want to change the value of aVar in far? We can't do it like this so we need some other method.
This is where pointers come in but first a bit more theory. In spin, the memory is divided up into byte (8 bit) sized pieces and each piece has its own address. Now, suppose that we know the address of a variable than we can get at it from anywhere in our program. A pointer is simple a variable that holds the address of another variable. In some programming languages there are special data types for pointers (C and C++), other languages don't allow them at all and others only allow them in very limited forms (Java). However, in spin, it is completely up to the programer to keep track of what is a pointer. This can allow some nice tricks while programming but can also be dangerous and allow bad programming practice but that is how spin works.
So, how do we get the address of a variable? You simply use the '@' operator. For example
VAR
byte aVar
word aVarAddress
PUB main
aVarAddress:=@aVar
Now aVarAddress holds the address of aVar, or, in other words aVarAddress is a pointer to aVar. Notice that I made aVarAddress a word. Because there are 65,536 bytes of memory in the propeller we need 16 bits or a word to be able to address all of them.
So now that we have an address we can use some other commands to change aVar.
All of the lines below do the same thing but in different ways.
The first line is the normal way to use variables when they are in the same object or local variables in the same object. The second line is the standard way of using a pointer to do the same thing. It says write the value 5 to the memory address that is in aVarAddress. The third line says write the value 5 to the memory address that is in aVarAddress plus 0. The last line could also be written like this
byte[noparse][[/noparse]aVarAddress+0]
But the last line just looks nicer
The last method is very useful with arrays. The way you would normally use it is like this
So arrayBase would get passed as a parameter and you shouldn't change it, arrayIndex is which element you want in the array and someNumber is the data to store in the array. You can also use this the other way around if you want to read the number in an array. For example
So, now you can get the address of a variable using the '@' operator and use that address to access the contents of that variable using the 'byte' operator. So time for another example
CON
ArrayElements=10
VAR
byte anArray[noparse][[/noparse]ArrayElements] 'an array of ten elements
word arrayPtr 'pointer to the start of the array
PUB main
arrayPtr:=@anArray 'the address of the first element in the array
foo(arrayPtr) 'call foo with the address of the array
PUB foo(ptr)|index
repeat index from 0 to ArrayElements-1 'set up a loop to go through every element in the array
byte[noparse][[/noparse]ptr][noparse][[/noparse]index]:=index 'write something to the array
Or for something more like what you need to use
CON
ArrayElements=10 'number of elements in the array
newStackSize=30 'stack size for the new cog
VAR
byte anArray[noparse][[/noparse]ArrayElements] 'an array
long stack[noparse][[/noparse]newStackSize]
PUB main
cognew(foo(@anArray),@stack) 'I used a shortcut here so that I don't need an extra variable
'the cog that this is running in will stop now
PUB foo(ptr)|index
index:=0 'set the index to 0 to start with. This is important because index is on a stack and it may not be 0
repeat 'loop forever
byte[noparse][[/noparse]ptr][noparse][[/noparse]index]:=index 'write something to the array
index++ 'increment the position in the array that we are writing to
if index>ArrayElements-1 'if we have got to the end of the array go back to the start
index:=0
This bit of code basically does everything that you want to do in your rxStr method except get the input and output.
Just a couple of notes to finish on.
1. Passing the address of a variable is really the same thing as passing by reference. The difference is that the compiler looks after some things for you. C++ and Java can do this.
2. Have a look at the 'word' and 'long' instructions. They can be used in the same way as 'byte'
3. If I have typed all of this without making a mistake I will be amazed
Well, I think this has ended up longer than the last post and I'm not good at writing! So, either this is a whole heap of waffling on about nothing or it may contain something useful
Sorry if you know all this stuff but I'm now sure what programming experience you have had. Hope this helps.
stevenmess, Wow man ! Thanks for taking the time to give me all that information. It is boosting me ahead in Spin at a fast rate
and I'm sure its helping all those new to Spin. It's helping more than you know and I will go over it a couple of times
to make sure that I understand everything fully.
stevenmess,
Would you check this my rxStr method. I have tried to change it according to your examples but
it is still not looping correctly. The first set of numbers that I send are coming up on the remote
prop correctly but when I try and enter the second set of numbers to send they just keep
scrolling across the bottom of the LCD on the transmitting end. I would assume that the pointer
coding is correct because it is getting far enough in the code to trransmit the first set of bytes.
This is the same problem that I was having before, its like it
PUB RxStr(Num_of_Chars,strPtr) | char, index
'strPtr holds the "16 bit location" of the arrays starting address.
byte[noparse][[/noparse]strPtr][noparse][[/noparse]index] := char 'Write char to the array
index++ 'increment array position
if Num_of_chars-- == 1 'If end of array execute
'the indented code, reset the
'array pointer,and go back
'to the start.
OK Guys, this is working now and I am not calling rxStr recursively
Take a look and give me your advise, my head is "Spin"-ing ...
'
·· byte[noparse][[/noparse] strPtr][noparse][[/noparse] index] := char········· 'Write char to the array ·· index++····························· 'increment array position ·· if Num_of_chars-- == 1
······································· 'If end of array execute ······································· 'the indented code, reset the ······································· 'array pointer,and go back ······································· 'to the start. ························· ····· Print_Status_To_LCD(@rxStr_array)················ ····· Transmit_Timer_values(@rxStr_array) ····· ····· data.rxflush ····· data_LCD.rxflush
I don't mean to keep loading you down with attachments but I am learning due to
the specifics of your examples. I have now made progress in the following areas of
my code per your instructions.
Thank you for helping with the following:
1) rxStr is now running without recursive code.
2) Received_Data is now running without recursive code.
3) When I press the "D" button on my keypad it is no longer calling Main.
4) Transmitting and recieving "9" bytes of data correctly and displaying ··· on the LCD in the correct format at the correct time.
Note: Please see attached Spin file with new up-dates.
Questions:
1) I have read and understand the basics of what locks are doing but a little cloudy ···how to pass the locks to all other Cogs running. Do I need to add another ··· "Lock_ID" parameter to all my cogs parameter list as well as FullDuplexSerials ? ··· Could you look at this latest attachment and give me an example.
2) I know that this has helped keep the Stack straight, when I call FullDuplexSerial ··· via my methods I assume that FullDuplexSerial is taking care of it's stack on ··· return, is this correct ?
3) Is there any other places in my code that you see where I am not taking care ··· of the Stack at this point ?
You both have helped me Trementously !
Thank You
JMLStamp2p
Both Props are now saving the "Math" results of the last "9" bytes received
to the Global varibles TValue_1, TValue_2 & TValue_3. I have incorperated
another Method that will Turn on LED's 16,19 & 23 respectivly with the
numbers that are received in the Global varibles. The Global varibles are being
cleared·before the method exits. Just a simple but fun way to verify the
program is doing the math right, a little fun is due :>)
Your code is starting to look good and I didn't even have to write it. Yes, it was a lot to write but I have already suggested that someone else look at. Maybe I will just make my standard reply to all questions "look at this thread and read the post about recursion and pointers!"
In the rxStr method I would change this
if Num_of_chars-- == 1 'Check to see if "9" bytes
'have been received.
to this
if index == Num_of_chars-1 'Check to see if "9" bytes
'have been received.
and remove the line that sets Num_of_chars back to 9. This just means that you can use it for any sized array rather than 9.
Another thing, in many methods you pass a pointer to an array but don't use it. For example Print_Status_to_LCD(rxStr_arrays), but you use rxStr_array (no s) instead. This is all right but you are either wasting a long on the stack due to the unused argument or not doing what you want to do.
Now for your questions
1. Just treat the value you got from lockNew as a pointer. You will need to either pass it to the other methods through the parameter list or make it a global variable. The global variable method will only work if your code is all in one object.
2. FullDuplexSerial doesn't actually have a stack for its cog because it is written in assembler
3. I can't see any problems except that you may need to add some locks so that two things don't try and call data or LCD_data at the same time.
stevenmess,
First, let me say that I believe anyone new to the Propeller would greatly benefit from your comments.
It's one thing to know spin but its another to teach it. You definetly can teach this stuff !
When I try and change the line in rxStr to: " if index == Num_of_chars-1" the Keypad will only accept "1"
digit and then it stops, I will look at it and see if I can figure out whats happening. I am adding another Cog
to monitor the states of "input pins "4..6" continually. These pins will be wired through (3) limit switchs to detect
what Global Timer Varible to set the Counter to. I have added a "test" method at the very bottom of my code
to see if my program will turn on an LED if pin "4" is grounded. For some reason it is not working, If I don't test
to see if pin 4 is at a logic "0" level and just toggle the pin it in a loop it works fine.
If I set a pin on the Prop to "input" is it pulled high or low internally or is it "Floating" ?
i analysed your Sourcecode just for me for a detailed understanding
methods that use data_lcd.tx:
PUB LCD_Setup (nur data_lcd.tx)
PUB RxStr ( data_lcd.tx und
receive one byte (wich is a bytecode of the pressed key on the keypad
depending on bytenumber 1,2,3... move pos of cursor on lcd to colummNr 1,2,3.. .
translate bytcode of pressed key into digit and send THIS SINGLE digit to LCD
using data_lcd.dec
decrement Num_of_chars
if 9 bytes were received Num_of_chars is = 1 then call method Print_Status_to_LCD
repeat the above endlessly
PUB Print_Status_to_LCD
set cursor on LCD to xy-Pos 19,2 send byte[noparse][[/noparse]0] as dec digit (first digit of first timervalue)
set cursor on LCD to xy-Pos 20,2 send byte as dec digit (second digit of first timervalue)
set cursor on LCD to xy-Pos 21,2 send byte as dec digit (third digit of first timervalue)
do the same with second / third timervalue in y=3, / y=4
PUB Print_Status_to_LCD_Receiver
independent running
PUB RxStr calls
- data_lcd.tx
- Print_Status_To_LCD
independent running
Recieved_Data does the same for the remote prop in the same way as like RxStr does for the LCD
it calls
- Print_Status_To_LCD_Reciever
now something about avoiding that different and independent calls of data_lcd.tx are crashing into each other:
if i remember right you have a display 4 rows each of 20 columms
the basic thing is to have a bytearray as a buffer for the charachters that should be diplayed on the lcd
this buffer is 4x20 Bytes = 80 bytes long
in the var section define
byte LCDBufferArray[noparse][[/noparse]80]
everytime you want to send a character to the lcd
in your sourcecode this is done by every call of data_lcd.tx() or data_lcd.dec()
this direct calls are replaced by a command that writes into the bufferarray at the right position
meaning the right row the right columm
f.e. you want to write into second row at columm 6
you would write that character at index 2*20+6 = 46
now there is a NEW method that does nothing else then read the LCDBufferArray and send the characters stored in the array
to the righgt positions (row and columm) on the LCD
now if the different methods RxStr Print_Status_to_LCD etc would write to the buffer whenever they want you would have collisions
by the writings
to avoid this you define a simple long as a lock-flag
long LCD_Buff_Array_locked
now before RxStr or Print_Status_to_LCD or etc start writing into LCDBufferArray the check
repeat while (LCD_Buff_Array_locked = "locked"
so the method will wait until LCD_Buff_Array_locked is "unlocked"
then instead of calling data_lcd.tx etc you call a method "PUB Write_to_LCD_Buff_Array(X,Y,char)
The "scarry" thing is that I undestand exactly what your saying, you guys are really helping me !
I know this sounds a little funny, everything is working correctly now for the most part and I find
myself afraid to make major changes in my program :>)
I know that I can make a copy of the code and always revert back to the previous, I know that it is
rreally the only way to learn. Im going to attempt what you have said and again Thank You for taking
the time that you have. There is no way that I would be where I am without yourself
and stevenmess.
I have added methods for input and methods to turn a pin "See latest attached code"
corresponding to the input that was made. NOTE: Only "1" input will ever
be made at a time. These are the problems that I am having:
I am attempting to write the code so that when a limit switch is made it will
ground the input to turn it on.
1) Method "Read_Limit_Switchs" is running in it's own Cog looking for input.
2) When I send the 1st set of numbers via the remote prop to the prop that ··· has these methods incorperated, it·will acknowledge and goto the "Output_4" ···method, turn on output "16" and start transmitting "TValue_1's" dec. Value ··· back to the remote prop. It will only "Respond" to this via the "Received_Data" ··· method and not via the "rxStr" method. Can't seem to figure out why ...
··· NOTE: I have·set the lines in "Read_Limit_Switchs"·to: ··· if Temp_4 := 1········· ······· Output_4
·· and· I have no wires attached to pin "4" its just floating. Is this a Logical "High" or "1" ? ·· to force the program to jump to the "PUB Output_4" Method just to check if it is working.
3) When I set it back to "if Temp_4 := 1" and try to have the program "sense" the state of input ··· "4" going·Low it does not respond. Pin "4" grounded at this point.
4) I must misunderstand how the inputs work, I am going to go back and read up on the initial state ··· of the props inputs. I was thinking that they were "Floating" unless set to be in a certain state.
5) I know that they are input unless·programmed to be outputs, are they pulled high or Low at this ··· point by internal resistors or just Floating·where I need to incorperate them myself ? I was ··· thinking the latter was the case.
if Temp_4 := 0 'If limit switch "1" is made goto "Output" 4 method
Output_4
does the following:
variable temp_4 is set to 0 and AFTER that the if-condition is evaluated
and then of course it's ALWAYS 0 and will NEVER call Output_4
do you mean
if Temp_4 has value 1 set value to zero and call Output_4 ?
if you want to write your program in this supercryptic c-fashion style
you write
if Temp_4~ 'If limit switch "1" is made goto "Output" 4 method
Output_4
"~" is the POST-clear command
take the value as it is do something with it and AFTER that (=POST) clear it
what about a much easyier readable way of programming?
if Temp_4 == 1 'If limit switch "1" is made goto "Output" 4 method
Temp_4 := 0
Output_4
quoted from the manual on page 226
INA is read-only and is not really implemented as a register but rather is just an address that,
when accessed as a source item in an expression, reads the Port A I/O pins directly at that
moment. In the result, a low (0) bit indicates the corresponding I/O pin senses ground, and a
high (1) bit indicates the corresponding I/O pin senses VDD (3.3 volts). Since the Propeller
is a CMOS device, the I/O pins sense anything above ½ VDD to be high, so a high means the
pin senses approximately 1.65 volts or higher.
inputs can't be written by ina(4) := 1 because the register is read only
you really have to connect the IO-Pin to Vdd to get a "1" from the INA-registerbit
how does the hardware look like that is connected to the Propeller-IO-PIN?
please post a drawing of it or use the special electric circuit-characters of the parallax truetype-font in a *.SPIN-File
I'm not sure how the thing should work
can you post a description?
i guess the following:
if a switch that is connected to IO-PIN 4 is closed then
turn on output 16
countdown from a startvalue stored in TValue_1
every second send actual value to remote-prop
decrement value until 0 is reached
turn off output 16
your construction
PUB Output_4 | x4, Retain_TValue_1
x4 := 0 'Set count destination to "0".
Retain_TValue_1 := TValue_1 'Retain the original value of TValue_1
repeat while x4 < TValue_1 'Repeat until TValue_1 = "0".
outa[noparse][[/noparse]16]:= 1 'Turn on output "16".
waitcnt(80_000_000 + cnt) 'Wait "1" second.
data.dec(TValue_1) 'Transmit the current dec.value of
'TValue_1 to the remote Prop.
TValue_1-- 'Decrement TValue_1, & Loop until
'TValue_1 = "0".
outa[noparse][[/noparse]16]:=0 'Turn output "16" off.
TValue_1 := Retain_TValue_1 'Return the Value of TValue_1 to the
'value it was before calling this
'Method.
is a little bit confusing
TValue_1 is a global variable
you are just counting down from this value
so to make thing easier to understand you should program something like this
PUB Output_4_new(Seconds) | ll_count ' my convention the beginning "ll_" means local long to make clear this is a local variable of type long
ll_count := Seconds 'Set count destination to Startvalue.
repeat while ll_count > 0 'Repeat until "0".
outa[noparse][[/noparse]16]:= 1 'Turn on output "16".
waitcnt(80_000_000 + cnt) 'Wait "1" second.
data.dec(ll_count) 'Transmit the current dec.value of
'count to the remote Prop.
ll_count-- 'Decrement count, & Loop until
'count = "0".
outa[noparse][[/noparse]16]:=0 'Turn output "16" off.
then the call of the method looks like this
if Temp_4~ 'If limit switch "1" is made goto "Output" 4 method
Output_4(TValue_1)
this code explains itself half: Output_4 is using TValue_1
but what for ? what does output_4 do?
there the NAMES of your methods should describe themselves
instead of PUB "Output_4"
something like PUB "Open_watervalve_1_for_X_seconds(p_Seconds)"
explains itself. No more comments needed !
that makes a program much better readable and easier to understand
it's the same with IO-Numbers
outa[noparse][[/noparse]16]:= 1 'Turn on output "16".
what was IO-PIN 16 for ?.....???
define a constant in the CON-section
c_Watervalve1 = 16
again
outa[noparse][[/noparse]c_Watervalve1] := 1
says everything itself
don't tell me this takes to much time to type on the PC-Keyboard
you have shortcuts for mark a word ctr-c ctrl-v for copy and paste
and how about the time spending scrolling up and down for that one line where you made the comment
pin16 is watervalve 1 ?
what about the time to find all the lines in your code if you want to change he IO-PIN
with a constant there is ONE place to change and all other places are changed too
if you define and use a constant
about not making major changes to your program:
if the program-concept stays like it is you will reach limits you can't go over
or trying to go over them will be like repairing a flat tire wich became flat through a screw
by screwing in a bigger screw into the whole where the air comes out.
And trying to find the right sized screw trying to screw it in as carefully as you can will take
MUCH more time then changing to a new tire
so my suggestion is:
make the change ! and the change ISN'T major it's a minor change
you are already using an array accessing by index
you are already reading out an array and send the content to the serial connection
so where's is the problem ?
some more ideas to reduce maintenance inside your program
'define constants
CON
c_EnterCommandMode = 254
c_SetCursor = 71
make a method
PUB SetCursorToXY(X,Y)
data_LCD.tx(c_EnterCommandMode)
data_LCD.tx(c_SetCursor)
data_LCD.tx(X)
data_LCD.tx(Y)
'call looks like this
'instead of
data_LCD.tx(254)
data_LCD.tx(71)
data_LCD.tx(20)
data_LCD.tx(2)
SetCursorToXY(20,2)
data_LCD.dec(RD_array)
posting a lot of new versions of code is OK but please
comment almost ALL lines of code and comment the lines that you have added or changed
otherwise i have to do a line by line compare to find out that
i do not have the same hardware as you and so i have to test almost everyhing inside my head
or in small pieces with my propeller-hardware
stefanL38,
Your examples make so much sense, I will make sure that I·go over·everything that you wrote.
I will also make comments as you suggested, its the very least that I can do for all your help.
Thanks so much for the time your taking !
JMLStamp2p
PS: I am off today and my hardware is at work, I will try the code out in the prop when I go
back on Tuesday and touch base with you again.·
Hello,
I have just updated my code with more comments and up-dated a
few methods thanks to help by stefanL38·& stevenmess. I am just
starting work this week and going over the code again. To update
everyone, the inputs 16,19 & 23 on my Prop proto board are outputs
that will be turning on a motor via some external circuitry. I will probally
use an opti-coupler and relay which will pull in a motor starter.
I have two Props communicating with each other via an "RF" link. They
transmit some Global Varibles "TValue_1, TValue_2 & TValue_3
back and forth to each other which are "Countdown Timer" varibles. The
motor and Timers I am controlling is on the "Quenching Station end".
I have the other prop in a remote office as we want to see
the prop counting down at the Quenching station by viewing the prop
in the remote office. Basically we·want to program these "Timers" via either location and monitor them at either locationvia an LCD.
The prop on the Quenching station end is receiving data sent by the
Ofice·prop. After it has received the data I can make output "16" go high
on the Quenching end by operating a limit switch. When I make the switch, LED "16"
will come on to simulate starting the motor and I can see the tranceiver
outputing the value of the global varible "TValue_1" to the remote Office prop.
I am doing this by veiwing the transmit light, it pulses every time the loop iterates
and when the loop terminates it turns output "16" off at the Quenching station end.
My problem right now is that the Limit switch at the Quench end only works after
I have received data·via the "Received_Data method" at the office location.
If I try and re-program the timers via the Keypad at the Quenching·station·the limit
switch does not operte the input.To Clarify, "Limit switch's are only at the Quenching
station end". I have just started going over the code so I will let everyone know what
I find and will Post if I need some more help.
Thank You for all the help that you have given,
JMLStamp2p
Please see attached file and the last post on page "3" of this thread regarding
Remote Control Props.·have added more comments to make it easier to read.
Regards,
JMLStamp2p
PS: I still am working on the last problem stated but have not solved it as of yet. ····
After I transmit data from the "Office Prop" to the "Quenching Station Prop" I can operate the Limit Switch attached to the Quenching station prop on "Input-4". It will turn on "LED 16" for the length of time that was in "TValue_1" when transmission took place and then the
output will turn off correctly.
My Problem:
If I then enter a new set of numbers for all three Timers via the Keypad at the "Quenching station". I am doing this to re-program the Timers with new "Countdown" values, the "Read_Limit_Switchs" Method is not being called for some reason. I know this because the LED on output "16" is not coming on. I have the "Read_Limit_Switchs" method running
in a repeat loop in a seperate Cog.
JMLStamp2p
I have edited your code and the attached file is the result. I simplified some of your if-elseif statements, made a few things into loops, used the pointers passed to methods to reduce the number of methods needed and also some other general cleaning up. Hopefully I haven't introduced any errors along the way because I don't have two propellers or a LCD to test it with.
I also put in a lock so that the LCD serial object doesn't get called by more than one object (I haven't commented it because I run out of time. If you don't understand how it is working just ask). You should probably also put in a lock for the other serial object as you may call it from more than one place at the same time.
I think the problems you were having were because you were using the wrong array in one of your methods but I think that is fixed now. Compare this to your version and hopefully you can learn something from what I've changed.
stevenmess2004 and stephanL38, "See attached File"
I did not get the attachment that you sent. but took the hint and changed a
few of the areas of code that you mentioned and now both sides are working !
I haven't included the locks yet but it thrills me to see that I can program the
Timers from either end and see the limit switch and outputs working. I realize
that I have alot of cleaning up to do but this puts the project at the last item
to accomplish "except for the Locks". At last I need to display the decrementing
count on the both LCD's as "PUB Output_4(Seconds) | Count_4" counts down.
I am working on that today and will read some more on "Locks", I think that I
am making the Lock thing too hard :>)
Thank you guys for getting me this far !
JMLStamp2p
Good Evening,
When I program the Timers via the Keypad at the Quenching Station Prop and pull the Limit Switch I get the following results. The following Method is called and I can see Timer
One decrementing every second as wanted, but when It makes the transistion from "100"
to "99" the digit in the hundreds collume doesn't change to "0" it reads "199" instead of "99". It does the same when it reach's "10" and makes the transistion to "9". I know that it is counting correctly because when it reach's "0" it turns the LED on pin "16" off. If I program "100" in timer one the LED will stay on for 100 seconds. For some reason it is not showing the "0's" when it makes the transistion from "10" to "09" the three digit display on the LCD reads "090" when "Count_4" reach's (9 seconds) Any suggestions ?
JMLStamp2p
PUB Output_4(Seconds) | Count_4
If I change the code to clear the LCD before Count is displayed to the screen
the numbers show up correctly.
PUB Output_4(Seconds) | Count_4 ·· data_LCD.tx(254) ·· data_LCD.tx(84) · 'Turn blinking cursor off. · ·· Count_4 := Seconds · 'Set Count_4 to TValue_1. ·································· ·· repeat while Count_4 > 0 ··· 'Repeat until Count_4 "or" Timer_1 = "0". ·· ······ outa[noparse][[/noparse]16]:= 1 ····· 'Turn on output "16". ····· ······ waitcnt(80_000_000 + cnt) ····· 'Wait "1" second.
······ data_LCD.tx(254) ······· data_LCD.tx(88) ······'Clear LCD display ····· ······ data_LCD.dec(Count_4) ······ 'Print current value of Count_4 to the LCD.
······ data.dec(Count_4) ······ 'Transmit current value of Count_4 to the Remote Prop. ······ ····························· ······ Count_4--·················· 'Decrement Count_4, & Loop until ·································· 'Count_4 = "0". ······ ·· outa[noparse][[/noparse]16]:=0···················· 'Turn output "16" off.
JMLStamp2p
So here is the file that I forgot to attach before...
Since you have already fixed the problem you may not want to look at this. However, some of it should make some things easier to understand and make your code shorter.
For the problem with the 1 try writing a space to the three positions where the number will go. What is probably happening is that the driver is only sending out the '9' so the '1' stays there even though you don't want it there.
Comments
I posted the above before I read the information about how the stack works which was very informable, Thank You. Please take a look at the file that I attached above and give me your opinion and suggestions. I am going to go back and read the above post and make sure that I understand it completely.
JMLStamp2p
inside the method RxStr you are calling RxStr recursive when key "D" is pressed
this will eat up memory over time
it is the same with the method Recieved_Data
inside if Num_of_nums-- == 1
the method RxStr runs in cogNr 2
and uses the method Print_Status_to_LCD which is sending data (using data_LCD.tx() )
to the LCD connected on PINs 2,3
your method Recieved_Data is running in CogNr 1
and uses the method Print_Status_To_LCD_Reciever (using data_LCD.tx TOO !)
to the LCD connected on PINs 2,3
this means:
two cogs that are running independent from each other but they are using the
same serial connection !!
The logic state of output-pins are "ored" inside the propellerchip
So if both methods use data_LCD.tx at the same time the logic state of PIN 2 and 3
will switch high and low UNDEFINED because of mixing the serial bitstreams of the two calls of data_LCD.tx() !!
here you have to change to a - what i call - shared bufferarray with a lock-mechanism (sometimes called "semaphore")
now a solution to thi sproblem could be:
write a method that does ONLY READ from the bufferarray and is the ONLY ONE to send data to the LCD
this method should be called endlessly from ONE place by a repeat-loop
The methods RxStr and Recieved_Data have to check if a Flag-variable is set to status "unlocked"
BEFORE they start WRITING into the bufferarray
if the status is "locked" then they just wait for status "unlocked" or the just exit without writing to the bufferarray
if status is "unlocked" they set the status themselve to "locked"
and AFTER that they start writing to the bufferarray
after FINISHING writing the status is set to "unlocked"
by this mechanism you avoid that both methods write to the bufferarray at THE SAME time
writing at the same time would mix up the data of the two calls
without the lock-mechanism mixing up the data could happen at ANY time beoause the methods RxStr and Recieved_Data are running
in different cogs
best regards
Stefan
Post Edited (StefanL38) : 3/13/2008 5:05:30 PM GMT
Thank you for your post, this is a little over my head so I might need some example code to help me get through it. I will definately start studying what you and stevenmess have posted. I was thinking about "Locking out" rxStr when data is being handled by the receiver
and vise versa anyway just as a precaution. It is unlikely that both will be writing to the LCD at the same time due to the nature of how our plant works but sometimes what can go wrong will :>( I tell ya, I am so darn excited about just being able to send and receive at this point I 'm afraid to touch the thing :>) I have been spending a tremendous amount of
time trying to get up to speed with the Propeller.
Thanks for your help guys,
JMLStamp2p
The only thing that the data entering the keypad and tranceiver are really doing "or what I want them to do" is transfer their value to the Global varibles TValue_1, TValue_2 & TValue_3. After this transfer of data takes place in my code could I just "pop" the data off the stacks since I wont really be using any previous return values after the data is sent to the LCD ? So after every "9" bytes are received via either Method both stacks are cleared and the Gloal varibles "updated" every time another "9" bytes are recieved.
JMLStamp2p
JMLStamp2p
I re-read your post above and it made perfect sense, the "locks" sound like it is very useful. I am still a little cloudy on the best way to Clear my Stacks. Can I use something like: longfill(@rxStr_Stack,0,20) to clear the stack and then reset the pointer if nessessary. And then do the same thing for my Received_Data Method ?
JMLStamp2p
Now for pointers.
As discussed in my previous post, one of the things that the stack is used for is passing parameters of methods. When you do something like this
The spin interpreter first stores where to come back to on the stack and then pushs the arguments (2 and 3 in this case) onto the stack. This is called passing by value in some programming languages. So the value you put in parenthesis are copied onto the stack. This means that you can do whatever you want to them without affecting the original value. This can be really handy. For example
This changes the value of x but it will not affect the value of aVar (it would mess up the loop in main if it did change aVar). This is all very good but what if we want to change the value of aVar in far? We can't do it like this so we need some other method.
This is where pointers come in but first a bit more theory. In spin, the memory is divided up into byte (8 bit) sized pieces and each piece has its own address. Now, suppose that we know the address of a variable than we can get at it from anywhere in our program. A pointer is simple a variable that holds the address of another variable. In some programming languages there are special data types for pointers (C and C++), other languages don't allow them at all and others only allow them in very limited forms (Java). However, in spin, it is completely up to the programer to keep track of what is a pointer. This can allow some nice tricks while programming but can also be dangerous and allow bad programming practice but that is how spin works.
So, how do we get the address of a variable? You simply use the '@' operator. For example
Now aVarAddress holds the address of aVar, or, in other words aVarAddress is a pointer to aVar. Notice that I made aVarAddress a word. Because there are 65,536 bytes of memory in the propeller we need 16 bits or a word to be able to address all of them.
So now that we have an address we can use some other commands to change aVar.
All of the lines below do the same thing but in different ways.
The first line is the normal way to use variables when they are in the same object or local variables in the same object. The second line is the standard way of using a pointer to do the same thing. It says write the value 5 to the memory address that is in aVarAddress. The third line says write the value 5 to the memory address that is in aVarAddress plus 0. The last line could also be written like this
But the last line just looks nicer
The last method is very useful with arrays. The way you would normally use it is like this
So arrayBase would get passed as a parameter and you shouldn't change it, arrayIndex is which element you want in the array and someNumber is the data to store in the array. You can also use this the other way around if you want to read the number in an array. For example
So, now you can get the address of a variable using the '@' operator and use that address to access the contents of that variable using the 'byte' operator. So time for another example
Or for something more like what you need to use
This bit of code basically does everything that you want to do in your rxStr method except get the input and output.
Just a couple of notes to finish on.
1. Passing the address of a variable is really the same thing as passing by reference. The difference is that the compiler looks after some things for you. C++ and Java can do this.
2. Have a look at the 'word' and 'long' instructions. They can be used in the same way as 'byte'
3. If I have typed all of this without making a mistake I will be amazed
Well, I think this has ended up longer than the last post and I'm not good at writing! So, either this is a whole heap of waffling on about nothing or it may contain something useful
Sorry if you know all this stuff but I'm now sure what programming experience you have had. Hope this helps.
and I'm sure its helping all those new to Spin. It's helping more than you know and I will go over it a couple of times
to make sure that I understand everything fully.
Great Examples !
JMLStamp2p
Would you check this my rxStr method. I have tried to change it according to your examples but
it is still not looping correctly. The first set of numbers that I send are coming up on the remote
prop correctly but when I try and enter the second set of numbers to send they just keep
scrolling across the bottom of the LCD on the transmitting end. I would assume that the pointer
coding is correct because it is getting far enough in the code to trransmit the first set of bytes.
This is the same problem that I was having before, its like it
PUB RxStr(Num_of_Chars,strPtr) | char, index
'strPtr holds the "16 bit location" of the arrays starting address.
index:= 0 'Set pointer to location "0"
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
data_LCD.tx(254)
data_LCD.tx(84)
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"
LCD_Setup
data.rxflush
data_LCD.rxflush
byte[noparse][[/noparse] strPtr]:= 0
bytefill(@rxStr_array,0,9)
RxStr(9,@rxStr_array)
if char == (70)
data_LCD.tx(254)
data_LCD.tx(88)
byte[noparse][[/noparse]strPtr][noparse][[/noparse]index] := char 'Write char to the array
index++ 'increment array position
if Num_of_chars-- == 1 'If end of array execute
'the indented code, reset the
'array pointer,and go back
'to the start.
Print_Status_To_LCD(@rxStr_array)
Transmit_Timer_values(@rxStr_array)
data.rxflush
data_LCD.rxflush
bytefill(rxStr_array,0,9)
index:= 0
I have uploaded the Spin file again just for Clarity.
JMLStamp2p
Take a look and give me your advise, my head is "Spin"-ing ...
'
·· byte[noparse][[/noparse] strPtr][noparse][[/noparse] index] := char········· 'Write char to the array
·· index++····························· 'increment array position
·· if Num_of_chars-- == 1
······································· 'If end of array execute
······································· 'the indented code, reset the
······································· 'array pointer,and go back
······································· 'to the start.
·························
····· Print_Status_To_LCD(@rxStr_array)················
····· Transmit_Timer_values(@rxStr_array)
·····
····· data.rxflush
····· data_LCD.rxflush
····· index:= 0
·····
····· data_LCD.tx(254)·····································
····· data_LCD.tx(71)··············
····· data_LCD.tx(5)
····· data_LCD.tx(2)
····· Num_of_chars := 9
I don't mean to keep loading you down with attachments but I am learning due to
the specifics of your examples. I have now made progress in the following areas of
my code per your instructions.
Thank you for helping with the following:
1) rxStr is now running without recursive code.
2) Received_Data is now running without recursive code.
3) When I press the "D" button on my keypad it is no longer calling Main.
4) Transmitting and recieving "9" bytes of data correctly and displaying
··· on the LCD in the correct format at the correct time.
Note: Please see attached Spin file with new up-dates.
Questions:
1) I have read and understand the basics of what locks are doing but a little cloudy
·· ·how to pass the locks to all other Cogs running. Do I need to add another
··· "Lock_ID" parameter to all my cogs parameter list as well as FullDuplexSerials ?
··· Could you look at this latest attachment and give me an example.
2) I know that this has helped keep the Stack straight, when I call FullDuplexSerial
··· via my methods I assume that FullDuplexSerial is taking care of it's stack on
··· return, is this correct ?
3) Is there any other places in my code that you see where I am not taking care
··· of the Stack at this point ?
You both have helped me Trementously !
Thank You
JMLStamp2p
Both Props are now saving the "Math" results of the last "9" bytes received
to the Global varibles TValue_1, TValue_2 & TValue_3. I have incorperated
another Method that will Turn on LED's 16,19 & 23 respectivly with the
numbers that are received in the Global varibles. The Global varibles are being
cleared·before the method exits. Just a simple but fun way to verify the
program is doing the math right, a little fun is due :>)
Thanks guys,
JMLStamp2p
In the rxStr method I would change this
to this
and remove the line that sets Num_of_chars back to 9. This just means that you can use it for any sized array rather than 9.
Another thing, in many methods you pass a pointer to an array but don't use it. For example Print_Status_to_LCD(rxStr_arrays), but you use rxStr_array (no s) instead. This is all right but you are either wasting a long on the stack due to the unused argument or not doing what you want to do.
Now for your questions
1. Just treat the value you got from lockNew as a pointer. You will need to either pass it to the other methods through the parameter list or make it a global variable. The global variable method will only work if your code is all in one object.
2. FullDuplexSerial doesn't actually have a stack for its cog because it is written in assembler
3. I can't see any problems except that you may need to add some locks so that two things don't try and call data or LCD_data at the same time.
First, let me say that I believe anyone new to the Propeller would greatly benefit from your comments.
It's one thing to know spin but its another to teach it. You definetly can teach this stuff !
When I try and change the line in rxStr to: " if index == Num_of_chars-1" the Keypad will only accept "1"
digit and then it stops, I will look at it and see if I can figure out whats happening. I am adding another Cog
to monitor the states of "input pins "4..6" continually. These pins will be wired through (3) limit switchs to detect
what Global Timer Varible to set the Counter to. I have added a "test" method at the very bottom of my code
to see if my program will turn on an LED if pin "4" is grounded. For some reason it is not working, If I don't test
to see if pin 4 is at a logic "0" level and just toggle the pin it in a loop it works fine.
If I set a pin on the Prop to "input" is it pulled high or low internally or is it "Floating" ?
i analysed your Sourcecode just for me for a detailed understanding
methods that use data_lcd.tx:
PUB LCD_Setup (nur data_lcd.tx)
PUB RxStr ( data_lcd.tx und
receive one byte (wich is a bytecode of the pressed key on the keypad
depending on bytenumber 1,2,3... move pos of cursor on lcd to colummNr 1,2,3.. .
translate bytcode of pressed key into digit and send THIS SINGLE digit to LCD
using data_lcd.dec
decrement Num_of_chars
if 9 bytes were received Num_of_chars is = 1 then call method Print_Status_to_LCD
repeat the above endlessly
PUB Print_Status_to_LCD
set cursor on LCD to xy-Pos 19,2 send byte[noparse][[/noparse]0] as dec digit (first digit of first timervalue)
set cursor on LCD to xy-Pos 20,2 send byte as dec digit (second digit of first timervalue)
set cursor on LCD to xy-Pos 21,2 send byte as dec digit (third digit of first timervalue)
do the same with second / third timervalue in y=3, / y=4
PUB Print_Status_to_LCD_Receiver
independent running
PUB RxStr calls
- data_lcd.tx
- Print_Status_To_LCD
independent running
Recieved_Data does the same for the remote prop in the same way as like RxStr does for the LCD
it calls
- Print_Status_To_LCD_Reciever
now something about avoiding that different and independent calls of data_lcd.tx are crashing into each other:
if i remember right you have a display 4 rows each of 20 columms
the basic thing is to have a bytearray as a buffer for the charachters that should be diplayed on the lcd
this buffer is 4x20 Bytes = 80 bytes long
in the var section define
byte LCDBufferArray[noparse][[/noparse]80]
everytime you want to send a character to the lcd
in your sourcecode this is done by every call of data_lcd.tx() or data_lcd.dec()
this direct calls are replaced by a command that writes into the bufferarray at the right position
meaning the right row the right columm
f.e. you want to write into second row at columm 6
you would write that character at index 2*20+6 = 46
byte[noparse][[/noparse]baseadressOf_LCD_BufferArray][noparse][[/noparse]index]
now there is a NEW method that does nothing else then read the LCDBufferArray and send the characters stored in the array
to the righgt positions (row and columm) on the LCD
now if the different methods RxStr Print_Status_to_LCD etc would write to the buffer whenever they want you would have collisions
by the writings
to avoid this you define a simple long as a lock-flag
long LCD_Buff_Array_locked
now before RxStr or Print_Status_to_LCD or etc start writing into LCDBufferArray the check
repeat while (LCD_Buff_Array_locked = "locked"
so the method will wait until LCD_Buff_Array_locked is "unlocked"
then instead of calling data_lcd.tx etc you call a method "PUB Write_to_LCD_Buff_Array(X,Y,char)
index := Y*20 + X
byte[noparse][[/noparse]baseadressOf_LCD_BufferArray][noparse][[/noparse]index] := char
then there has to be a method that is reading the LCDBufferArray all the time
and send the content of all 80 bytes to the LCD
an improvement could be to have a second buffer and to compare which byte has CHANGED and only send the changed bytes to the LCD
so this is a short description in halfcode or pseudo-code what you have to program
best regards
Stefan
you do it not directly but indirectly
The "scarry" thing is that I undestand exactly what your saying, you guys are really helping me !
I know this sounds a little funny, everything is working correctly now for the most part and I find
myself afraid to make major changes in my program :>)
I know that I can make a copy of the code and always revert back to the previous, I know that it is
rreally the only way to learn. Im going to attempt what you have said and again Thank You for taking
the time that you have. There is no way that I would be where I am without yourself
and stevenmess.
JMLStamp2p
I have added methods for input and methods to turn a pin "See latest attached code"
corresponding to the input that was made. NOTE: Only "1" input will ever
be made at a time. These are the problems that I am having:
I am attempting to write the code so that when a limit switch is made it will
ground the input to turn it on.
1) Method "Read_Limit_Switchs" is running in it's own Cog looking for input.
2) When I send the 1st set of numbers via the remote prop to the prop that
··· has these methods incorperated, it·will acknowledge and goto the "Output_4"
·· ·method, turn on output "16" and start transmitting "TValue_1's" dec. Value
··· back to the remote prop. It will only "Respond" to this via the "Received_Data"
··· method and not via the "rxStr" method. Can't seem to figure out why ...
··· NOTE: I have·set the lines in "Read_Limit_Switchs"·to:
··· if Temp_4 := 1·········
······· Output_4
·· and· I have no wires attached to pin "4" its just floating. Is this a Logical "High" or "1" ?
·· to force the program to jump to the "PUB Output_4" Method just to check if it is working.
3) When I set it back to "if Temp_4 := 1" and try to have the program "sense" the state of input
··· "4" going·Low it does not respond. Pin "4" grounded at this point.
4) I must misunderstand how the inputs work, I am going to go back and read up on the initial state
··· of the props inputs. I was thinking that they were "Floating" unless set to be in a certain state.
5) I know that they are input unless·programmed to be outputs, are they pulled high or Low at this
··· point by internal resistors or just Floating·where I need to incorperate them myself ? I was
··· thinking the latter was the case.
Regards,
JMLStamp2p
your code
does the following:
variable temp_4 is set to 0 and AFTER that the if-condition is evaluated
and then of course it's ALWAYS 0 and will NEVER call Output_4
do you mean
if Temp_4 has value 1 set value to zero and call Output_4 ?
if you want to write your program in this supercryptic c-fashion style
you write
"~" is the POST-clear command
take the value as it is do something with it and AFTER that (=POST) clear it
what about a much easyier readable way of programming?
quoted from the manual on page 226
INA is read-only and is not really implemented as a register but rather is just an address that,
when accessed as a source item in an expression, reads the Port A I/O pins directly at that
moment. In the result, a low (0) bit indicates the corresponding I/O pin senses ground, and a
high (1) bit indicates the corresponding I/O pin senses VDD (3.3 volts). Since the Propeller
is a CMOS device, the I/O pins sense anything above ½ VDD to be high, so a high means the
pin senses approximately 1.65 volts or higher.
inputs can't be written by ina(4) := 1 because the register is read only
you really have to connect the IO-Pin to Vdd to get a "1" from the INA-registerbit
how does the hardware look like that is connected to the Propeller-IO-PIN?
please post a drawing of it or use the special electric circuit-characters of the parallax truetype-font in a *.SPIN-File
I'm not sure how the thing should work
can you post a description?
i guess the following:
if a switch that is connected to IO-PIN 4 is closed then
turn on output 16
countdown from a startvalue stored in TValue_1
every second send actual value to remote-prop
decrement value until 0 is reached
turn off output 16
your construction
is a little bit confusing
TValue_1 is a global variable
you are just counting down from this value
so to make thing easier to understand you should program something like this
then the call of the method looks like this
this code explains itself half: Output_4 is using TValue_1
but what for ? what does output_4 do?
there the NAMES of your methods should describe themselves
instead of PUB "Output_4"
something like PUB "Open_watervalve_1_for_X_seconds(p_Seconds)"
explains itself. No more comments needed !
that makes a program much better readable and easier to understand
it's the same with IO-Numbers
what was IO-PIN 16 for ?.....???
define a constant in the CON-section
c_Watervalve1 = 16
again
says everything itself
don't tell me this takes to much time to type on the PC-Keyboard
you have shortcuts for mark a word ctr-c ctrl-v for copy and paste
and how about the time spending scrolling up and down for that one line where you made the comment
pin16 is watervalve 1 ?
what about the time to find all the lines in your code if you want to change he IO-PIN
with a constant there is ONE place to change and all other places are changed too
if you define and use a constant
about not making major changes to your program:
if the program-concept stays like it is you will reach limits you can't go over
or trying to go over them will be like repairing a flat tire wich became flat through a screw
by screwing in a bigger screw into the whole where the air comes out.
And trying to find the right sized screw trying to screw it in as carefully as you can will take
MUCH more time then changing to a new tire
so my suggestion is:
make the change ! and the change ISN'T major it's a minor change
you are already using an array accessing by index
you are already reading out an array and send the content to the serial connection
so where's is the problem ?
some more ideas to reduce maintenance inside your program
instead of a lot of hardcoded
'define constants
CON
c_EnterCommandMode = 254
c_SetCursor = 71
make a method
posting a lot of new versions of code is OK but please
comment almost ALL lines of code and comment the lines that you have added or changed
otherwise i have to do a line by line compare to find out that
i do not have the same hardware as you and so i have to test almost everyhing inside my head
or in small pieces with my propeller-hardware
regards
Stefan
Your examples make so much sense, I will make sure that I·go over·everything that you wrote.
I will also make comments as you suggested, its the very least that I can do for all your help.
Thanks so much for the time your taking !
JMLStamp2p
PS: I am off today and my hardware is at work, I will try the code out in the prop when I go
back on Tuesday and touch base with you again.·
I have just updated my code with more comments and up-dated a
few methods thanks to help by stefanL38·& stevenmess. I am just
starting work this week and going over the code again. To update
everyone, the inputs 16,19 & 23 on my Prop proto board are outputs
that will be turning on a motor via some external circuitry. I will probally
use an opti-coupler and relay which will pull in a motor starter.
I have two Props communicating with each other via an "RF" link. They
transmit some Global Varibles "TValue_1, TValue_2 & TValue_3
back and forth to each other which are "Countdown Timer" varibles. The
motor and Timers I am controlling is on the "Quenching Station end".
I have the other prop in a remote office as we want to see
the prop counting down at the Quenching station by viewing the prop
in the remote office. Basically we·want to program these "Timers"
via either location and monitor them at either locationvia an LCD.
The prop on the Quenching station end is receiving data sent by the
Ofice·prop. After it has received the data I can make output "16" go high
on the Quenching end by operating a limit switch. When I make the switch, LED "16"
will come on to simulate starting the motor and I can see the tranceiver
outputing the value of the global varible "TValue_1" to the remote Office prop.
I am doing this by veiwing the transmit light, it pulses every time the loop iterates
and when the loop terminates it turns output "16" off at the Quenching station end.
My problem right now is that the Limit switch at the Quench end only works after
I have received data·via the "Received_Data method" at the office location.
If I try and re-program the timers via the Keypad at the Quenching·station·the limit
switch does not operte the input.To Clarify, "Limit switch's are only at the Quenching
station end". I have just started going over the code so I will let everyone know what
I find and will Post if I need some more help.
Thank You for all the help that you have given,
JMLStamp2p
Remote Control Props.·have added more comments to make it easier to read.
Regards,
JMLStamp2p
PS: I still am working on the last problem stated but have not solved it as of yet.
····
output will turn off correctly.
My Problem:
If I then enter a new set of numbers for all three Timers via the Keypad at the "Quenching station". I am doing this to re-program the Timers with new "Countdown" values, the "Read_Limit_Switchs" Method is not being called for some reason. I know this because the LED on output "16" is not coming on. I have the "Read_Limit_Switchs" method running
in a repeat loop in a seperate Cog.
JMLStamp2p
I also put in a lock so that the LCD serial object doesn't get called by more than one object (I haven't commented it because I run out of time. If you don't understand how it is working just ask). You should probably also put in a lock for the other serial object as you may call it from more than one place at the same time.
I think the problems you were having were because you were using the wrong array in one of your methods but I think that is fixed now. Compare this to your version and hopefully you can learn something from what I've changed.
I did not get the attachment that you sent. but took the hint and changed a
few of the areas of code that you mentioned and now both sides are working !
I haven't included the locks yet but it thrills me to see that I can program the
Timers from either end and see the limit switch and outputs working. I realize
that I have alot of cleaning up to do but this puts the project at the last item
to accomplish "except for the Locks". At last I need to display the decrementing
count on the both LCD's as "PUB Output_4(Seconds) | Count_4" counts down.
I am working on that today and will read some more on "Locks", I think that I
am making the Lock thing too hard :>)
Thank you guys for getting me this far !
JMLStamp2p
When I program the Timers via the Keypad at the Quenching Station Prop and pull the Limit Switch I get the following results. The following Method is called and I can see Timer
One decrementing every second as wanted, but when It makes the transistion from "100"
to "99" the digit in the hundreds collume doesn't change to "0" it reads "199" instead of "99". It does the same when it reach's "10" and makes the transistion to "9". I know that it is counting correctly because when it reach's "0" it turns the LED on pin "16" off. If I program "100" in timer one the LED will stay on for 100 seconds. For some reason it is not showing the "0's" when it makes the transistion from "10" to "09" the three digit display on the LCD reads "090" when "Count_4" reach's (9 seconds) Any suggestions ?
JMLStamp2p
PUB Output_4(Seconds) | Count_4
data_LCD.tx(254)
data_LCD.tx(84)
'Turn blinking cursor off.
Count_4 := Seconds
'Set Count_4 to TValue_1.
repeat while Count_4 > 0
'Repeat until Count_4 "or" Timer_1 = "0".
outa[noparse][[/noparse]16]:= 1
'Turn on output "16".
waitcnt(80_000_000 + cnt)
'Wait "1" second.
data_LCD.tx(254)
data_LCD.tx(71)
data_LCD.tx(18)
data_LCD.tx(2)
data_LCD.dec(Count_4)
'Print current value of Count_4 to the LCD. at location
'Col-18, Row-2.
data.dec(Count_4)
'Transmit current value of Count_4 to the Remote Prop.
Count_4-- 'Decrement Count_4, & Loop until
'Count_4 = "0".
outa[noparse][[/noparse]16]:=0 'Turn output "16" off.
the numbers show up correctly.
PUB Output_4(Seconds) | Count_4
·· data_LCD.tx(254)
·· data_LCD.tx(84)
· 'Turn blinking cursor off.
·
·· Count_4 := Seconds
· 'Set Count_4 to TValue_1.
··································
·· repeat while Count_4 > 0
··· 'Repeat until Count_4 "or" Timer_1 = "0".
··
······ outa[noparse][[/noparse]16]:= 1
····· 'Turn on output "16".
·····
······ waitcnt(80_000_000 + cnt)
····· 'Wait "1" second.
······ data_LCD.tx(254)
······ · data_LCD.tx(88)
····· ·'Clear LCD display
·····
······ data_LCD.dec(Count_4)
······ 'Print current value of Count_4 to the LCD.
······ data.dec(Count_4)
······ 'Transmit current value of Count_4 to the Remote Prop.
······
·····························
······ Count_4--·················· 'Decrement Count_4, & Loop until
·································· 'Count_4 = "0".
······
·· outa[noparse][[/noparse]16]:=0···················· 'Turn output "16" off.
JMLStamp2p
That will retain the positioning of the ls digit.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Harley Shanko
did you test your SPIN-Prg with a teminalsoftware on your PC.
This means connect the serial-port not to the LCD but to a PC running a terminalsoftware that shows the hexadecimal values of the bytes received?
a very good one is Br@y's Terminal V1.9 (see attached file)
it has an Option for auto connect/disconnect by winning/loosing the focus
so you can even use it on the same pins as the propeller is programmed (PIN 30, PIN31)
please use the hexadecimal mode to see EVERY byte (= all the non ASCII-codes too)
so if this is working correct it has something to do with your display
regards
Stefan
Since you have already fixed the problem you may not want to look at this. However, some of it should make some things easier to understand and make your code shorter.
For the problem with the 1 try writing a space to the three positions where the number will go. What is probably happening is that the driver is only sending out the '9' so the '1' stays there even though you don't want it there.