millis() equivalent in PIC

Thread Starter

ak52

Joined Oct 15, 2014
230
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
 

Papabravo

Joined Feb 24, 2006
21,228
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:
// delay = N*T

for(i = 1, i < N, ++i)  ;    //Loop for N*T that does no useful work
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,
 

Thread Starter

ak52

Joined Oct 15, 2014
230
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??
 

Papabravo

Joined Feb 24, 2006
21,228
Yes. The output compare device in many processors is a great way to create a schedule of periodic events that require processing.
 

djsfantasi

Joined Apr 11, 2010
9,163
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.
 

Papabravo

Joined Feb 24, 2006
21,228
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?
 

ErnieM

Joined Apr 24, 2011
8,377
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.
 

Papabravo

Joined Feb 24, 2006
21,228
Timer0 interrupt does not depend on an external clock; RTC or otherwise.
http://www.microcontrollerboard.com/pic-timer0-tutorial.html
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.
 

Thread Starter

ak52

Joined Oct 15, 2014
230
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:
int sampletime_ms=0,present_time=0,previous_time=0,diff_time=0;
sampletime_ms = 1000; 
void run_PID()
{
  present_time = get_time_from_rtc();
  diff_time = (present_time - previous_time);
  if(diff_time > sampletime_ms)
  {
  //run control loop
  previous_time = present_time;
  }
}
I am now looking for a replacement for the "get_time_from_rtc()" function.
 

ErnieM

Joined Apr 24, 2011
8,377
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.
 

Papabravo

Joined Feb 24, 2006
21,228
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.
 

Thread Starter

ak52

Joined Oct 15, 2014
230
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:
if(TMR1 == TMR2)
{
//generate interrupt
//disable pwm.
}
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?
 

Thread Starter

ak52

Joined Oct 15, 2014
230
Edit: Digging through the data sheet it says
When the OCx module is enabled, the Input/Output (I/O) pin direction is controlled by the Output
Compare x module. The Output Compare x module returns the I/O pin control back to the appropriate LATx and TRISx control bits when it is disabled. When the Simple PWM with Fault Protection
Input mode is enabled, the OCFA/OCFB Fault pins must be configured as inputs by setting the
respective TRISx bits. Enabling this special PWM mode does not configure the OCFA/OCFB Fault
pins as inputs.
So using OCx is not an option for me :!
 

Papabravo

Joined Feb 24, 2006
21,228
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:
if(TMR1 == TMR2)
{
//generate interrupt
//disable pwm.
}
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?
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:

Thread Starter

ak52

Joined Oct 15, 2014
230
i my have found a suitable alternative,its quiet simple actually,
Code:
while(counter < counter_limit)
{
if(counter % 1000 == 0)      //executes the loop exactly after 1000 cycles
{
        //run my control loop
        run_PID();
}
counter++
//continue with the rest of the operations
}
 

Papabravo

Joined Feb 24, 2006
21,228
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?
 

JWHassler

Joined Sep 25, 2013
306
i my have found a suitable alternative,its quiet simple actually,
Code:
while(counter < counter_limit)
{
if(counter % 1000 == 0)      //executes the loop exactly after 1000 cycles
{
        //run my control loop
        run_PID();
}
counter++
//continue with the rest of the operations
}
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.
 

Thread Starter

ak52

Joined Oct 15, 2014
230
yes sir,there is an interrupt which interrupts at 200ms.
I actually forgot to mention that and I also modified my looping slightly.
Code:
short counter = 0;
if (counter % 5 == 0)  //updates  every second
  {
if(counter > 100)
counter = 0;
//run the control function
run_PID();
}
//ISR
void __attribute__((__interrupt__, no_auto_psv)) _T3Interrupt(void)
{
  /* Interrupt Service Routine code goes here */
  IFS0bits.T3IF = 0; //Clear Timer3 interrupt flag
counter++;
}
 
Last edited:
Top