incPID Routine - Help Needed


Closed Thread
Results 1 to 40 of 64

Hybrid View

  1. #1
    Join Date
    Jan 2011
    Location
    Sydney, Australia
    Posts
    172


    Did you find this post helpful? Yes | No

    Default Re: incPID Routine - Help Needed

    Hi Henrik,

    I can use a serial display connected to the 18F24321's EUSART or a standard HD44780 type. I suspect the serial device with take up much less overhead once the whole system is running but for the time being I will use the standard HD44780.

    I will continue with the PID implementation using the smaller 24V 200W scooter motor - I feel much safe playing with lower, less lethal voltages for my prototyping purposes. Once I have that system operating successfully I will then step up to the 180V treadmill motor.

    I will send regular progress details as I achieve various project milestones.

    Cheers
    Barry
    VK2XBP

  2. #2
    Join Date
    Jan 2011
    Location
    Sydney, Australia
    Posts
    172


    Did you find this post helpful? Yes | No

    Default Re: incPID Routine - Help Needed

    OK, I now have a PIC18F2431 with acounter set up on Timer1 and a time base set up on Timer0.
    The counter was pretty straight forward but i have a few questions regarding the operation of Timer0

    1/. Timer Pre-Load
    Timer0 is a 16 bit timer which gives an output as it rolls over from $FFFF to 0.
    An 8MHZ clock speed will provide one instruction every 500ns. For a 100Hz time base (10ms period) I would need 20000 instruction cycles (20000 x 500ns = 10ms).
    A free running timer wiith no pre-load would roll over every 65536th cycle so to achieve a 20000 cycle roll over I need to pre-load the timer with 65536 - 20000 = 45536.
    All good - nice clean theory however, a 45536 pre-load results in ~50Hz time base!

    Here is my code:

    Code:
    #CONFIG
        CONFIG OSC = IRCIO
        CONFIG FCMEN = ON
        CONFIG IESO = OFF
        CONFIG PWRTEN = ON
        CONFIG BOREN = ON
        CONFIG BORV = 42
        CONFIG WDTEN = OFF
        CONFIG WDPS = 512
        CONFIG WINEN = OFF
        CONFIG PWMPIN = OFF
        CONFIG LPOL = HIGH
        CONFIG HPOL = HIGH
        CONFIG T1OSCMX = OFF
        CONFIG MCLRE = ON
        CONFIG STVREN = ON
        CONFIG LVP = OFF
        CONFIG DEBUG = OFF
        CONFIG CP0 = ON
        CONFIG CP1 = ON
        CONFIG CP2 = ON
        CONFIG CP3 = ON
        CONFIG CPB = OFF
        CONFIG CPD = OFF
        CONFIG WRT0 = OFF
        CONFIG WRT1 = OFF
        CONFIG WRT2 = OFF
        CONFIG WRT3 = OFF
        CONFIG WRTC = OFF
        CONFIG WRTB = OFF
        CONFIG WRTD = OFF
        CONFIG EBTR0 = OFF
        CONFIG EBTR1 = OFF
        CONFIG EBTR2 = OFF
        CONFIG EBTR3 = OFF
        CONFIG EBTRB = OFF
    #ENDCONFIG
    
    ' Set up interrupt routine
    INCLUDE "DT_INTS-18.bas"       ; Base Interrupt System
    INCLUDE "ReEnterPBP-18.bas"    ; Include if using PBP interrupts
    ASM
    INT_LIST  macro    ; IntSource,        Label,  Type, ResetFlag?
            INT_Handler   TMR0_INT,  _ISR,   PBP,  yes
        endm
        INT_CREATE            ; Creates the interrupt processor
    ENDASM
    
    @   INT_ENABLE  TMR0_INT  ; Enable Timer 0 Interrupts
    
    ' Define LCD registers and bits
    Define	LCD_DREG	PORTB
    Define	LCD_DBIT	4
    Define	LCD_RSREG	PORTA
    Define	LCD_RSBIT	1
    Define	LCD_EREG	PORTA
    Define	LCD_EBIT	2
    Define	LCD_BITS	4
    Define	LCD_LINES	2
    
    ' Set up Internal Oscillator @ 8MHz
    DEFINE OSC 8
    OSCCON = %01110010   ' Internal oscillator, 8MHz
    
    
    ' Set up Timer0 
    T0CON = %00001000       ' Timer off
                            ' 16 bit
                            ' Internal clock
                            ' Prescaler not assigned
    T0CON.7 = 1             ' Start Timer0
    
    ' Set up I/O Ports
    ANSEL0 = 0              ' No analogue input, all digital
    TRISA = 0               ' ALL PORTA as outputs
    PORTA = 0               ' All outputs low
    TRISB = 0               ' ALL PORTB as outputs
    PORTB = 0               ' All outputs low
    TRISC = 0               ' Set PORTC as output
    PORTC = 0               ' All outputs low
    
    
    Pause 100
    LCDOUT $FE,1,"   Baztronics   "
    Pause 100
    
    TMR0_Reload CON 55750   ' Reload value for ~100Hz interrupt frequency at 8MHz, prescaler 1:1
    TMR0_Temp VAR WORD      ' Temporary variable use for reloading the timer
    
    LED1 VAR PortC.2
    
    Main:
        Pause 100
        Goto Main
    
    ' This is the interrupt routine for the TMR0 interrupt.
    ISR:
    
        T0CON.7 = 0                         ' Stop timer
    
        TMR0_Temp.LOWBYTE = TMR0L
        TMR0_Temp.HighByte = TMR0H          ' Get current "time"
        TMR0_Temp.LOWBYTE = TMR0L
    '    TMR0_Temp.HighByte = TMR0H
        TMR0_Temp = TMR0_Temp + TMR0_Reload ' Add reload value to get correct interval
    
        TMR0L = TMR0_Temp.LOWBYTE
        TMR0H = TMR0_Temp.HIGHBYTE          ' Move result back to timer 
        TMR0L = TMR0_Temp.LOWBYTE
    '    TMR0H = TMR0_Temp.HIGHBYTE
        
        T0CON.7 = 1                         ' Start timer
        Toggle LED1
    @ INT_RETURN
    I know my internal oscillator is operating at 8MHz because my LCDOUT commands work properly.
    Can anyone explain why the time base is not as predicted?

    2/. TMR0L and TMR0H
    The datasheet states that "TMR0H is not the high byte of the timer/counter in 16bit mode, but is actually a buffered version of the high byte of Timer0" and that it "is not directly readable nor writable."
    It goes on to explain that "TMR0H is updated wth the contents of the high byte of TMR0 during a read of TMR0L" The same conditions apply for write operations.
    The way I understand this, I must read the TMR0L first, this transfers the buffered data to the high byte of TMR0H and THEN I can read the high byte directly.
    Obviously I have mis understood the operation as this does not work.
    The only way I can get the timer to provide a stable time base is to read TMR0L twice and TMR0H once OR read TMR0H twice and TMR0L once.

    Would someone be able to describe how/why the low and high bytes of TMR0 should be read/written?

    Cheers
    Barry
    VK2XBP

  3. #3
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,612


    Did you find this post helpful? Yes | No

    Default Re: incPID Routine - Help Needed

    Hi Barry,

    1) Are you sure you're not getting 100Hz interrupt rate? You are using TOGGLE in the ISR so if the interrupt frequency IS 100Hz it will blink the LED at 50Hz.

    2) The way I understand it is that when reading TMR0 you should first read TMR0L, this triggers a transfer (in hardware, nothing you need to worry about) of the content of the actual high byte of the counter into TMR0H which you can then read. When writing you do it the other way around, first load TMR0H then you write TMR0L and that write operation triggers a transfer from TMR0H to the actual high byte of counter.

    This hardware buffering prevents the possibillity of the counter rolling over in between reading or writing each individual byte but it's important to do it the correct order.

    If you're not using TMR2 for anything it might be easier to use that since it doesn't really require reloading. It counts from 0 to PR2, generates an interrupt and start over at 0. No need to stop the timer, get the value, add reload, write new value and restart the timer. Its only 8 bits but it does have a prescaler so and postscaler so you should be able to get 100Hz. Of course using TMR1 works too!

    /Henrik.

  4. #4
    Join Date
    Jan 2011
    Location
    Sydney, Australia
    Posts
    172


    Did you find this post helpful? Yes | No

    Default Re: incPID Routine - Help Needed

    Hi Henrik,

    Thanks for the quick reply.

    1/. Yes, I wasn't using a LED to check the time base - I measured the frequency on my digital oscilloscope

    2/. Hmmm.... OK, I will do a bit more playing around to see what I can come up with.

    I will check out TMR2 and see if I can get it working as a 100Hz time base.

    Lot's of ways to skin a cat. I will try them all and see what I can learn along the way

    Cheers
    Barry
    VK2XBP

  5. #5
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,612


    Did you find this post helpful? Yes | No

    Default Re: incPID Routine - Help Needed

    Hi Barry,
    I'm still not convinced....
    If the PIC is toggling the output at 100Hz the measured frequency will be 50Hz because it turns the output ON 50 times per second and OFF 50 times per second. Replace the TOGGLE LED1 with LED1 = 1 : PAUSEUS 100 : LED1 = 0 and see if that convinces you it actually IS interrupting at 100Hz.

    /Henrik.

  6. #6
    Join Date
    Jan 2011
    Location
    Sydney, Australia
    Posts
    172


    Did you find this post helpful? Yes | No

    Default Re: incPID Routine - Help Needed

    Hi Henrik,

    Yes, you were right on both instances.

    I now have a nice, stable 100Hz time base and most importantly - I understand why

    Next step is to incorporate the timer/counter setup with the PWM motor drive to count encoder steps.
    From there it is a matter of getting it all to work with the PID routine.

    Once more I am indebted to you, Henrik, and the other forum members for the invaluable assistance. Thank you.

    Cheers
    Barry
    VK2XBP

  7. #7
    Join Date
    Jan 2011
    Location
    Sydney, Australia
    Posts
    172


    Did you find this post helpful? Yes | No

    Default Re: incPID Routine - Help Needed

    Hi All,

    I am pleased to report that I now have the PID system operating with a timer/counter configuration (100Hz time base) AND a 4 x 20 serial LCD being driven via the 18F2431's EUSART and HSEROUT commands.
    My original design only allowed single direction motor drive but the new design has the motor driven by a MOSFET H-Bridge allowing for forward and reverse direction.

    Henrik, you suggested to limit the pid_Out result to allow only positive drive outcomes for my original design. Now that I have forward and reverse direction capability, should I re-introduce positive and negative pid_Out drive conditions or do you think switching the motor/H-Bridge between forward and reverse state will cause undue stress on the motor?

    Cheers
    Barry
    VK2XBP

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