millis() equivalent in PIC

Discussion in 'Embedded Systems and Microcontrollers' started by ak52, Apr 9, 2015.

  1. ak52

    Thread Starter Member

    Oct 15, 2014
    145
    4
    Hello,
    Is there any way I can replicate the millis() function using in audrino to PIC,without using RTC?
    An algorithm of some sort would be helpful.

    Thanks in advance,
    AK
     
  2. Papabravo

    Expert

    Feb 24, 2006
    10,144
    1,791
    You can write a small piece of code that executes a loop some number of times. If you know how long it takes to go around the loop one time, call this number T. It should be evident that if you go around the loop N times it will result in a delay of:
    Code (Text):
    1.  
    2. // delay = N*T
    3.  
    4. for(i = 1, i < N, ++i)  ;    //Loop for N*T that does no useful work
    5.  
    6.  
    It really is not a very satisfactory way to do things, because it sacrifices the most important principle of programming which it to create the appearance of simultaneity by doing things as fast as you can in parallel,
     
  3. ak52

    Thread Starter Member

    Oct 15, 2014
    145
    4
    As you pointed simultaneity is important.The MCU should not abandon its basic routine until the loop ends.
    This function will be used to trigger important repetitive contol loops,(Like PID control loop).
    Is there any other alternative to this??
     
  4. Papabravo

    Expert

    Feb 24, 2006
    10,144
    1,791
    Yes. The output compare device in many processors is a great way to create a schedule of periodic events that require processing.
     
  5. djsfantasi

    AAC Fanatic!

    Apr 11, 2010
    2,809
    834
    Disclaimer: this is provided for information only. I investigated this approach before deciding on an Arduino.

    Does your PIC support a timer interrupt (timer0)? If so, you can increment a global variable as appropriate. This link uses the technique.
    http://romanblack.com/one_sec.htm
    If I'm off base, let me know.
     
  6. Papabravo

    Expert

    Feb 24, 2006
    10,144
    1,791
    He did say without using RTC, which I believe is the acronym for Real Time Clock. The basic implementation of an RTC is a periodic interrupt. I would argue that an an output compare module can be periodic, but it does not have to be. It can be aperiodic or follow an arbitrary application derived schedule. If there are long idle periods in the schedule then there is no need to process periodic interrupts. Interrupts only occur when required. Does that meet your requirements?
     
  7. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,388
    1,605
    What compiler are you using for your PIC? For example, if you have the XC8 compiler the MPLAB XC8 C Compiler User’s Guide in the Appendix describes lot of useful functions in the standard library, including:
    __DELAY_MS, __DELAY_US, __DELAYWDT_US, __DELAYWDT_MS
    Synopsis
    __delay_ms(x) // request a delay in milliseconds
    __delay_us(x) // request a delay in microseconds
    __delaywdt_ms(x) // request a delay in milliseconds
    __delaywdt_us(x) // request a delay in microseconds

    It is quite worthwile to peek into the "docs" folder and see what other good information in there.
     
    djsfantasi likes this.
  8. djsfantasi

    AAC Fanatic!

    Apr 11, 2010
    2,809
    834
  9. Papabravo

    Expert

    Feb 24, 2006
    10,144
    1,791
    Timer 0 depends on the oscillator frequency which can be external or internal on a PIC. The term RTC is ambiguous at best. It can be a Time of Day Clock Calender device or in a RTOS it can be any timer, like Timer 0, that provides a periodic interrupt. The literature is neither clear nor precise on this point. I guess the OP/TS will need to provide us with some clarification on this point.
     
  10. ak52

    Thread Starter Member

    Oct 15, 2014
    145
    4
    Thanks guys,for all your replies,
    I am using XC16 compiler.(dsPIC33ep128mc202).
    There are in built delay functions(__delayms(),__delayus() and __delay32() etc) ,but i would like to keep them as a last resort.
    The idea behind using an RTC was that i could get the data(current time) and past time and take a decision on whether to run my control loops or not, by checking the time difference.

    Something like this:
    Code (Text):
    1.  
    2. int sampletime_ms=0,present_time=0,previous_time=0,diff_time=0;
    3. sampletime_ms = 1000;
    4. void run_PID()
    5. {
    6.   present_time = get_time_from_rtc();
    7.   diff_time = (present_time - previous_time);
    8.   if(diff_time > sampletime_ms)
    9.   {
    10.   //run control loop
    11.   previous_time = present_time;
    12.   }
    13. }
    14.  
    I am now looking for a replacement for the "get_time_from_rtc()" function.
     
  11. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,388
    1,605
    Ah, well that is very different. Never mind...

    One thing I frequently drop into my projects is a 1mS interrupt fired off a timer, I've never used a PIC16 but I believe any of the timerc can do this too. The basic thing is to use the timer match with appropoaite prescaller and such to generate the 1mS interrupt. Inside the routine I update a global variable (I call it tick) and also catch things like button debouncing/checking.

    It's always nice to just check some global variable that gets updated in the background to see what my code should do next.
     
    JWHassler likes this.
  12. Papabravo

    Expert

    Feb 24, 2006
    10,144
    1,791
    As I said previously this function is superbly handed by an Output Compare Module. It automates the scheduling of the next compare event even if there is some latency in getting to and processing the interrupt. You can set them up to interrupt every miilisecond come rain or shine.
     
  13. ak52

    Thread Starter Member

    Oct 15, 2014
    145
    4
    Hmm, yes the output compare module will do the trick,but i have a few basic doubts regarding this module,i generally use a high speed pwm modules for pwm generation and ignore this completely.This is my first time attempting to use it so please correct me if i am wrong anywhere.
    Firstly all my MCU pins are already assigned,currently the output compare module pins are digital outputs for my LCD,it is possible to only compare ,and not generate any PWM after comparison?,something like this:
    Code (Text):
    1.  
    2. if(TMR1 == TMR2)
    3. {
    4. //generate interrupt
    5. //disable pwm.
    6. }
    7.  
    I am assuming that if i set the OC1CON1bits.OCM = 0x00; would this disable the PWM generation and i can continue using the pin as a digital output for my LCD?
     
  14. ak52

    Thread Starter Member

    Oct 15, 2014
    145
    4
    Edit: Digging through the data sheet it says
    So using OCx is not an option for me :!
     
  15. AfdhalAtiffTan

    Active Member

    Nov 20, 2010
    117
    11
    If you need millis() just for the elapsed time counter, why not just use a timer interrupt which increment a long variable in 1ms? It will overflows in around 49days.
     
    djsfantasi likes this.
  16. Papabravo

    Expert

    Feb 24, 2006
    10,144
    1,791
    That is not quite the way it works. You don't compare two timers to each other, but rather you compare a timer to a COMPARE REGISTER with a fixed value. Each time there is an interrupt you can adjust the value to adapt to changing circumstances.

    It is true that PWM requires the output compare function, but check the number of channels that you have available. It would not surprise me to find a device with an output compare channel that had no connection to external pins. That's the one you want.

    What datasheet are you looking at?
    In the dsPIC30F6011A there is a Timer4/Timer5 module that has the output compare feature you need without the complication of having to deal with output pins.
     
    Last edited: Apr 10, 2015
  17. ak52

    Thread Starter Member

    Oct 15, 2014
    145
    4
    i my have found a suitable alternative,its quiet simple actually,
    Code (Text):
    1.  
    2. while(counter < counter_limit)
    3. {
    4. if(counter % 1000 == 0)      //executes the loop exactly after 1000 cycles
    5. {
    6.         //run my control loop
    7.         run_PID();
    8. }
    9. counter++
    10. //continue with the rest of the operations
    11. }
    12.  
     
  18. Papabravo

    Expert

    Feb 24, 2006
    10,144
    1,791
    How are counter and counter_limit declared? If they are defined as int you may be in for some serious difficulty.
    Ask you self the question?
    0x7FFF + 1 = 0x8000
    Is 0x8000 < 0x7FFF if they are declared int --> YES
    Is 0x8000 < 0x7FFF if they are declared unsigned int --> NO

    What happens when you exit the while loop? Do counter and counter_limit get reinitialized before you enter the loop again?
     
  19. JWHassler

    Member

    Sep 25, 2013
    201
    33
    You need an interrupt: what you've shown here will be executed every 1000 trips through the loop, sure, but its timing/rep-rate will be at the mercy of all other operations.

    Further back in this thread, a one-millisecond timer-interrupt was suggested, and I second that.
    Anytime I meet a new microprocessor, I write a tight, low-latency timer interrupt. It's an aid to problem-analysis, as well as -solution.
     
  20. ak52

    Thread Starter Member

    Oct 15, 2014
    145
    4
    yes sir,there is an interrupt which interrupts at 200ms.
    I actually forgot to mention that and I also modified my looping slightly.
    Code (Text):
    1.  
    2. short counter = 0;
    3. if (counter % 5 == 0)  //updates  every second
    4.   {
    5. if(counter > 100)
    6. counter = 0;
    7. //run the control function
    8. run_PID();
    9. }
    10. //ISR
    11. void __attribute__((__interrupt__, no_auto_psv)) _T3Interrupt(void)
    12. {
    13.   /* Interrupt Service Routine code goes here */
    14.   IFS0bits.T3IF = 0; //Clear Timer3 interrupt flag
    15. counter++;
    16. }
    17.  
     
    Last edited: Apr 14, 2015
Loading...