Shop OBEX P1 Docs P2 Docs Learn Events
Remote Control Props: - Page 2 — Parallax Forums

Remote Control Props:

2

Comments

  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-13 16:07
    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
  • StefanL38StefanL38 Posts: 2,292
    edited 2008-03-13 16:53
    Hello John,

    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
  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-13 20:30
    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
  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-13 20:45
    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
  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-13 20:59
    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
  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-13 23:38
    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
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-03-14 07:19
    Sorry this took so long. Work, tafe, the Aussie meeting on irc and sleeping got in the waysmile.gif

    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.
    aVar:=5
    byte[noparse][[/noparse]aVarAddress]:=5
    byte[noparse][[/noparse]aVarAddress][noparse][[/noparse]0]:=5
    


    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 nicersmile.gif

    The last method is very useful with arrays. The way you would normally use it is like this
    byte[noparse][[/noparse]arrayBase][noparse][[/noparse]arrayIndex]:=someNumber
    


    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
    someNumber:=byte[noparse][[/noparse]arrayBase][noparse][[/noparse]arrayIndex]
    



    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 smile.gif

    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 usefulsmile.gif

    Sorry if you know all this stuff but I'm now sure what programming experience you have had. Hope this helps.
  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-14 13:42
    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.

    Great Examples !
    JMLStamp2p
  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-14 15:13
    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.

    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
  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-14 15:22
    stevenmess & StefanL38

    I have uploaded the Spin file again just for Clarity.
    JMLStamp2p
  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-14 15:52
    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

    ····· index:= 0
    ·····
    ····· data_LCD.tx(254)·····································
    ····· data_LCD.tx(71)··············
    ····· data_LCD.tx(5)
    ····· data_LCD.tx(2)

    ····· Num_of_chars := 9
  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-14 17:33
    stevenmess and Stefan38,

    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
  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-14 20:00
    Ok, last attached file for today :>)

    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
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-03-14 22:35
    Your code is starting to look good and I didn't even have to write itsmile.gif. 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!"smile.gif

    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 assemblersmile.gif

    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.
  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-15 14:59
    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" ?
  • StefanL38StefanL38 Posts: 2,292
    edited 2008-03-15 15:02
    Hello John,

    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
  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-15 15:27
    stefanL38,

    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
  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-15 19:52
    Hello guys,

    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
  • StefanL38StefanL38 Posts: 2,292
    edited 2008-03-15 22:00
    Hello John,

    your code

       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

    instead of a lot of hardcoded

      data_LCD.tx(254)
      data_LCD.tx(71)
      data_LCD.tx(20)
      data_LCD.tx(2)
    
    
    



    '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


    regards

    Stefan
  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-17 04:08
    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.·
  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-18 23:57
    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
  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-19 19:58
    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.
    ····
  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-19 20:19
    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
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-03-20 00:40
    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 withsmile.gif.

    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.
  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-20 16:38
    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
  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-20 18:53
    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

    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.
  • JMLStamp2pJMLStamp2p Posts: 259
    edited 2008-03-20 19:16
    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
  • HarleyHarley Posts: 997
    edited 2008-03-20 19:32
    Or, display a leading zero (or space) if less than 100 and again if less than 10.

    That will retain the positioning of the ls digit.

    yeah.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Harley Shanko
  • StefanL38StefanL38 Posts: 2,292
    edited 2008-03-20 20:27
    Hello John,

    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
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-03-20 20:47
    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.
Sign In or Register to comment.