Operator problem


Closed Thread
Results 1 to 16 of 16
  1. #1
    Join Date
    Dec 2012
    Location
    Türkiye
    Posts
    103

    Default Operator problem

    Hi ;

    I'm having an interesting problem with the following programme block ..

    Just to note that , The program works as written and compiled with it's current form below . I'm getting RB0 interrupts on every falling edge of PORTB.0 and when the programme goes to interrupt block it just clears the TMR1 register and RB0 int. flag and waits for the next RB0 interrupt by reading the INTF(RB0 int flag) continuously . . And when the INTF goes high (RB0 interrupt occurs) thus it leaves the while wend cycles and gets the variable in the TMR1 so that I can measure a period .. As I said , I can measure and display the period with this method ... But when It comes to calculating the revolutions per minute (RPM) with the ( * ) operator in the bold written code it just goes mad and misdisplays the RPM value on the screen ..

    What I wanna know is : Why the ( * ) multiplication operator doesn't work in the code below and how come the ( */ ) operator gives me the right result ??

    I mean let's say , time and rpm are word variables and time=19827 (us) , you know that 1 minute equals to 60 * 10^6 (us) = which is written in the form of 6000 * 10000 (just to state them both in word format)

    So : When we take ( */ ) operator the result is supposed to be

    6000*/ 10000 = 234375 (since the */ gives me the middle 16 bit of the result , as if we divide the result by 256)
    rpm=div32 19827
    result ===> rpm=11.82 thus "11"

    Both the project on breadboard and PROTEUS give me the correct result ( 3026 )

    How is that possible ? and why ( * ) operand doesn't work while it is supposed to work ?

    Thanks in advance !

    Code:
    '------
    DISABLE
    
    
    intblock:
    
    
    TMR1=0   
    INTF=0     'RB0/INT FLG
    
    
    WHile INTF=0
    @ NOP
    wend
    
    
    time=TMR1
    rpm=6000*/10000
    rpm=div32 time
    
    
    INTF=0'FLG
    
    
    resume
    
    
    enable
    '------
    Last edited by gunayburak; - 1st April 2014 at 19:08.

  2. #2
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,517


    Did you find this post helpful? Yes | No

    Default Re: Operator problem

    Hi,
    Which device are you using?
    I'm not sure you can access the full TMR1 register pair in one go - even with RD16 enabled. On some devices the 16bit timers are buffered and you need to read the two bytes in the correct order or you'll get the wrong result. On the other hand, you're saying that you can measure and display the period with this very method which I find a bit strange.

    You could try something like
    Code:
    DISABLE
    
    intblock:
      INTF=0     'RB0/INT FLG
      T1CON.0 = 1    'Start timer 1
    
      WHILE INTF=0
    @ NOP
      wend
    
      T1CON.0 = 0 'Stop timer 1
    
      time.lowbyte = TMR1L
      time.highbyte = TMR1H
    
      rpm=6000*/10000
      rpm=div32 time
    
      TMR1L = 0   ' Clear TMR1 so it's ready for next round.
      TMR1H = 0
    /Henrik.

  3. #3
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default Re: Operator problem

    DIV32 requires that PBP's system variables be loaded with a 32-bit value from a prior 16x16 bit multiplication.
    The multiplication has to use at least 1 WORD variable.

    But when you specify a multiplication of 2 constants ... the multiplication is done a compile-time as part of the optimization (constant folding).
    The system variables never get loaded, because the multiplication was not done at run-time.

    The mid-word multiplier is never done at compile-time, even if it has two constants.
    It's always done at run-time, and the system variables do get loaded.

    And ... TMR1 is declared as a WORD variable in the .pbpinc files.
    It's OK to read the entire Timer1 value as long as two conditions are met ... the Timer must be stopped, and RD16 must NOT be set.
    DT

  4. #4
    Join Date
    Dec 2012
    Location
    Türkiye
    Posts
    103


    Did you find this post helpful? Yes | No

    Default Re: Operator problem

    Quote Originally Posted by HenrikOlsson View Post
    Hi,
    Which device are you using?
    I'm not sure you can access the full TMR1 register pair in one go - even with RD16 enabled. On some devices the 16bit timers are buffered and you need to read the two bytes in the correct order or you'll get the wrong result. On the other hand, you're saying that you can measure and display the period with this very method which I find a bit strange.

    You could try something like
    Code:
    DISABLE
    
    intblock:
      INTF=0     'RB0/INT FLG
      T1CON.0 = 1    'Start timer 1
    
      WHILE INTF=0
    @ NOP
      wend
    
      T1CON.0 = 0 'Stop timer 1
    
      time.lowbyte = TMR1L
      time.highbyte = TMR1H
    
      rpm=6000*/10000
      rpm=div32 time
    
      TMR1L = 0   ' Clear TMR1 so it's ready for next round.
      TMR1H = 0
    /Henrik.
    That's a nice code too , Thanks Henrik . I am using PIC16F628A and apparently I can reach the entire TMR1 at once ...

  5. #5
    Join Date
    Dec 2012
    Location
    Türkiye
    Posts
    103


    Did you find this post helpful? Yes | No

    Default Re: Operator problem

    Quote Originally Posted by Darrel Taylor View Post
    DIV32 requires that PBP's system variables be loaded with a 32-bit value from a prior 16x16 bit multiplication.
    The multiplication has to use at least 1 WORD variable.

    But when you specify a multiplication of 2 constants ... the multiplication is done a compile-time as part of the optimization (constant folding).
    The system variables never get loaded, because the multiplication was not done at run-time.

    The mid-word multiplier is never done at compile-time, even if it has two constants.
    It's always done at run-time, and the system variables do get loaded.

    And ... TMR1 is declared as a WORD variable in the .pbpinc files.
    It's OK to read the entire Timer1 value as long as two conditions are met ... the Timer must be stopped, and RD16 must NOT be set.
    You're amazing Darrel ! .. That's such a nice explanation and mind-flashing answer .. Just outta curiosity .. Where do you get such knowledges from ? I mean we can't even get these infos from the compilers reference manual ...

    Thank you guys for your prompt answers !

  6. #6
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default Re: Operator problem

    Thanks gunayburak,

    Everything about PBP is completely transparent.
    The libraries (*.lib), macro files (*.mac), the generated assembly language (*.asm) and resulting Listing files (*.LST) are all plain text files that can be viewed with NotePad or similar text editors.

    With only 15-years or so of studying those files ... and attempting to solve hundreds of other peoples problems (cause I can't make my own), and you too will know everything there is to know about PicBasic Pro.

    Except for about a million things.
    DT

  7. #7
    Join Date
    Dec 2012
    Location
    Türkiye
    Posts
    103


    Did you find this post helpful? Yes | No

    Default Re: Operator problem

    Yet there is one more problem digging my mind ..
    Was I not supposed to get 11 according to the calculation I did at my first post ?
    How come I get 3026 ( which is the correct mathematical result and the result I expect to get with only * operand ??

    Thanks once again ..

  8. #8
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default Re: Operator problem

    Assuming the operations are being done at run-time ...
    Internally, both * and */ do the same 16x16 bit multiplication, and the system variables contain the same 32-bit "product".

    For the mid-word multiplier, the middle two bytes are then copied to the result variable, in this case rpm.
    That result is then discarded and rpm is assigned the value from the DIV32, which used the 32-bit value in the system variables, not the mid-word value.
    Code:
    rpm=6000*/10000  ; <-- This result in rpm is discarded
    rpm=div32 time
    The same thing applies to the High-Word multiplier **.
    DT

  9. #9
    Join Date
    Dec 2012
    Location
    Türkiye
    Posts
    103


    Did you find this post helpful? Yes | No

    Default Re: Operator problem

    Thanks to both of you darrel and henrik ...

    By the night I will be done with my pid rpm controller unit ...
    Thanks to henrik's code which helped me so much with my projects ..
    I modified his code to suit my rpm controller

  10. #10
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,517


    Did you find this post helpful? Yes | No

    Default Re: Operator problem

    Hi,
    Excellent!
    All credits goes to Darrel though, I pretty much missed the ball alltogether on this one. Which is OK because I learned a thing or two from it, th e
    I'm glad to hear the PID routine gets used and that it works. Out of curiosity, modifications were needed?

    /Henrik.

  11. #11
    Join Date
    Dec 2012
    Location
    Türkiye
    Posts
    103


    Did you find this post helpful? Yes | No

    Default Re: Operator problem

    Hi Henrik ,
    Sorry for the late answer .. I was busy with becoming a freak of PID
    Well , the first modification I did is removing the acceleration feedforward and velocity feedforward block of the PID routine just to see the raw PID feedback mechanism works without any help of those and also due to lack of the memory of my pic16f628a ..
    And I just added a line on the main routine where it applies the calculated P+I+D = pid output to the CCPM registers .. But unlike yours , I used such a code below ;
    '------------------------
    ..
    ..
    gosub PID
    duty=duty+pid_out
    ..
    ..
    '-----------------------------

    Yet there is one more question digging my mind like hell about one code that you wrote in the INTEGRAL routine ...

    IF pid_Eit>0 then pid_Ei=0

    ...........

    Shouldn't we have cleared the pid_Ei temporary integral error accumulator storage for also the condition pid_Eit<0 ??
    Last edited by gunayburak; - 4th April 2014 at 09:49.

  12. #12
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,517


    Did you find this post helpful? Yes | No

    Default Re: Operator problem

    Hi,
    Yeah, someday I need to update the routine to allow optional inclusion of the feedforward terms. At the time, PBP3 wasn't available so we had no conditional compilation.

    If it works it works but I'm not quite sure about the duty=duty+pid_out, that way you keep accumulating the output of the filter. But perhaps that's what you want.

    Right, the nagging question then...
    pid_EiT is a WORD variable so as far as PBP is concerned it can never be <0. It's either 0 or positive.
    The idea behind that piece of code is to allow the accumulator to grow even if the calculations "this time", due to truncation etc, would otherwise yeild a result of 0. It's not perfect but at least it guarantees that the accumulator WILL grow no matter how small the error and/or integral gain is.

    Does that answer your question?

    /Henrik.

  13. #13
    Join Date
    Dec 2012
    Location
    Türkiye
    Posts
    103


    Did you find this post helpful? Yes | No

    Default Re: Operator problem

    Hi Henrik ;

    Why are you not sure about the code line ;

    duty=duty+pid_Out

    CCP1CON.4=DUTY.0
    CCP1CON.5=DUTY.1
    CCPR1L=DUTY>>2




    Since we're trying to reach to a setpoint and that is the RPM in our case , The only way to keep the motor speed/RPM stable is giving an actual duty cycle command with an additional (positive or negative ) error dependant variable which is duty=duty+pid_Out ...
    In such an equation in case we calculate a "zero" error , our duty doesn't need to change and keeps its duty as long as the error is zero , but when the error changes pid_out variable contributes to the next duty cycle with a positive or negative value depending the errors sign ... (I interpret and speak through the code you and Darrel created)

    Let's take your code part which is applying the code directly to the registers as it is ...

    HPWM 1 , pid_out,10000
    pause 10 '''''''' this delay must be the lag , dead time I suppose , which I find very accurate for the slow responsing systems but I can't say the same for fast responsing systems ..

    Well ... Now let's say we're at the desired RPM level for the motor , then what ? , pid_out is gonna be zero since there is no error ? Which means unpowering the motor for a short time or loosing the voltage on the motor till the balance condition breaks ...

    I may be wrong with all those thoughts since I am a newbie engineering student ... Please enlighten and correct me if I'm wrong with those written above ..

    Regards

    Thanks for your counsel ..

  14. #14
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,517


    Did you find this post helpful? Yes | No

    Default Re: Operator problem

    Hi,

    Just because the error is zero doesn't mean the output from PID filter is.
    Yes, the proportional term will be zero but the integral term won't neccesarily be. It'll be whatever it took to get the error to zero and therefor the output of the pid filter will be equal to the integral term - which you then continously add to your dutycycle untill a negative error develops, at which point the integral term decreases and eventually goes negative. Again the RPM reaches the setpoint but now the pid filter output is negative so it'll keep deceasing the duty cycle untill a positive error develops and the cycle repeats.

    The velocity feedforward basically does what you say. It'll provide a "startingpoint" from which the PID then can add or subtract depending on the dynamic response of the system. That startingpoint then varies depending on the setpoint so you can tweak to work pretty well without any PID at all, then the PID handles the "disturbances" and load varioations only. But now you don't have the velocity feedforward in the code any more ;-)

    The Pause 10 was just part of the example. Of course the sample time, how often the filter is executed needs to be adapted to the system you're trying to control. 100Hz will be WAY to fast for controlling the temperature in a house while it'll be WAY to slow for controlling the current thru a motorwinding - for example.

    But again, I'm not saying you're doing anything wrong. In fact you may very well be doing it right I'm just trying to explain how I understand it. And, most importantly, as long as it works for you whatever is fine by me!

    /Henrik.

  15. #15
    Join Date
    Dec 2012
    Location
    Türkiye
    Posts
    103


    Did you find this post helpful? Yes | No

    Default Re: Operator problem

    Thanks for your splendid explanations Henrik .. I've just seen once again that I misunderstood the integral term of the PID control system ... But I'm trying to match the theoritical knowledge in my head and the code you've written .. especially the lines pointing out the Integral term calcs .

    We keep accumulating the error over and over and again during a period of cycles that we choose in the programme (Ti) And then we divide the sum of the errors to Ti ... Thus we get the arithmetic mean of the error sum , Am I Right ? On the other hand "the integral" in math gives us the field under the curve .... That's where I find the code a bit awkward .. Because after summing the errors we just do not use it in the process but using the arithmetic mean of the errors we summed ...

    Please set my mind free of these mind killing questions digging and eating my head ...

  16. #16
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,517


    Did you find this post helpful? Yes | No

    Default Re: Operator problem

    Hi,
    Correct.
    1) We accumulate (in the pid_Ei variable) the error over Ti number of samples
    2) We multiply the accumulated error by the integral gain
    3) We divide the result by Ti to get the average error over Ti number of samples.
    4) We add the result to the PID_I variable and make sure it doesn't violate or min/max settings.
    5) We clear the accumulator (the pid_Ei variable).

    So, PID_I is the actual integral term, it holds the history of all past errors and is what's used to "build" the final output together with the P and D terms (and the feedforward terms). The accumulation/averaging kind of low pass filters the integral term. If you you don't want to use it then simply use a Ti of 1 - it'll then update the I-term every cycle with the error at exactly that sample.

    There are different ways of implementing a PID filter and this is only one of them. Another change I'm thinking of implementing is the option to have the differential term work from the feedback instead of the setpoint.

    /Henrik.

Similar Threads

  1. Can someone please explain the operator */
    By triton99 in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 29th November 2011, 15:16
  2. // Division Operator
    By Dick Ivers in forum mel PIC BASIC Pro
    Replies: 4
    Last Post: - 9th September 2011, 15:27
  3. Exponential Operator
    By andrewroz in forum mel PIC BASIC Pro
    Replies: 11
    Last Post: - 31st October 2007, 09:00
  4. '*/' operator
    By jblackann in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 18th January 2007, 21:00
  5. math operator LOG
    By Eyal in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 23rd July 2004, 00:45

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts