CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Millis() function in CCS

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
emelyjose



Joined: 13 Nov 2016
Posts: 5

View user's profile Send private message

Millis() function in CCS
PostPosted: Sun Nov 13, 2016 5:06 pm     Reply with quote

Hi how is it going. I'm new to the forum and programming and I really would like you to give me an idea or a program to be able to monitor how much time a program actually runs in microseconds from start to finish and save it in a variable.

Really what I want is to implement a code of a PID to control the temperature of an oven but the code is written for the Arduino compiler. And the only break I have is that I found a function called millis() and not really how to measure the execution time of my program.

If it helps someone here, I leave them the code of the program so that they can analyze it and then tell me that they think.

I once saw that this can be done using a Timer but I have searched and searched in many parts of the internet and I do not find anything similar to the Millis () function implemented in CCS.

Really the code is missing a lot but my main priority is how to learn to use millis () in ccs.
Code:

#include <18F4550.h>
#device ADC=10
#use delay(crystal=20000000)

#FUSES PUT                      //Power Up Timer
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOVREGEN                 //USB voltage regulator disabled
#FUSES NOPBADEN                 //PORTB pins are configured as digital I/O on RESET
#FUSES NOLPT1OSC                //Timer1 configured for higher power operation
#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOXINST                  //Extended instruction set disabled

#define LCD_RS_PIN PIN_D0
#define LCD_RW_PIN PIN_D1
#define LCD_ENABLE_PIN PIN_D2
#define LCD_DATA4 PIN_D3
#define LCD_DATA5 PIN_D4
#define LCD_DATA6 PIN_D5
#define LCD_DATA7 PIN_D6
#include <lcd.c>

int timeChange, SampleTime = 100; // Seteamos el tiempo de muestreo en 100 Mili Segundo
int NewSampleTime=0;// A modificar......
int16 control=0;
unsigned long lastTime, now;
double Temp=0, salida, Setpoint, ITerm, lastInput,kp, ki, kd, outMin,outMax, Min, Max;
 
void main()
{
   setup_timer_2(t2_div_by_4,249,1);   //Configuracion de Timer 2 para establecer frec. PWM a 1kHz
   setup_ccp1(ccp_pwm);                //Configurar modulo CCP1 en modo PWM
   set_pwm1_duty(0);                   //Dejo en cero la salida PWM
   
   setup_adc_ports(AN0);              //Configurar ADC (Lectura de temperatura) setup_adc_ports(AN0||VSS_VREF);
   setup_adc(adc_clock_internal);      //Reloj interno para la conversion analoga digital)
   set_adc_channel(0);                 //Seleccionar Canal 0 para sensor de Temperatura
   
   LCD_INIT();                         //Inicializo el LCD
   LCD_PUTC("\f");                     //Limpio el LCD
   
     
   while(TRUE)
   { 
     
      Temp=read_adc()*5000.0/1024.0;
      lcd_gotoxy(1,1);
      printf(lcd_putc,"Temp: %f",Temp/10);
     
      unsigned long now = millis(); // xxx duracion del programa viene del timer 0   unsigned long now = millis();
      double timeChange = (double)(now - lastTime);
      if(timeChange>=SampleTime)// Determina si hay que ejecutar el PID o retornar de la función.
         { 
         
            /* Calculamos todas las variables de error. */
            double error = Setpoint - Temp;
            ITerm += (ki * error);
            if(ITerm> outMax) ITerm= outMax;
               else if(ITerm< outMin) ITerm= outMin;
            double dInput = (Temp - lastInput);
           
            /* Calculamos la función de salida del PID. */
            salida = kp * error + ITerm - kd * dInput;
               if(salida > outMax) salida = outMax;
                else if(salida < outMin) salida = outMin;
            lcd_gotoxy(1,4);
            printf(lcd_putc,"u(ley Con): %ld   ",control);
           
 /* Guardamos el valor de algunas variables para el próximo ciclo de cálculo. */
            lastInput = Temp;
            lastTime = now;
         }   
           
/* Establecemos los valores de las constantes para la sintonización. */
         double SampleTimeInSec = (double) SampleTime /100;
         kp = Kp;
         ki = Ki * SampleTimeInSec;
         kd = Kd / SampleTimeInSec;
         
         /* si el usuario decide cambiar el tiempo de muestreo durante el funcionamiento, Ki y Kd tendrán
         que ajustarse para reflejar este cambio. */           
         if (NewSampleTime > 0)
            {
            double ratio = (double)NewSampleTime / (double)SampleTime;
            ki *= ratio;
            kd /= ratio;
            SampleTime = (unsigned long)NewSampleTime;
            }
           
         if(Min > Max) return;
            {
            outMin = Min;
            outMax = Max;
            }
            if(salida > outMax) salida = outMax;
            else if(salida < outMin) salida = outMin;
            if(ITerm> outMax) ITerm= outMax;
            else if(ITerm< outMin) ITerm= outMin;
            }   
         
        delay_ms(1000);
         
      //---------------------------------------------------------------------------//
     
      /*lcd_gotoxy(1,2);
      printf(lcd_putc,"SetPoint: %2.2f C   ",R/10);
      lcd_gotoxy(1,3);
      printf(lcd_putc,"Error: %2.2f C   ",e/10);*/
     
      /* Cuanto tiempo pasó desde el último cálculo. */
   }
Ttelmah



Joined: 11 Mar 2010
Posts: 19338

View user's profile Send private message

PostPosted: Mon Nov 14, 2016 3:46 am     Reply with quote

Before looking at time, there are some problems elsewhere. For instand 'double' does not exist. The largest type that exists in CCS for the PIC18, is a single. It won't error, but it'll just replace double with single. Honestly though you also need to understand 'why'. Even single precision maths is slow. On your chip a single precision division takes nearly 300uSec at your clock rate. Imagine how much worse it'd be using double. Also there is almost nothing in the world that needs this type of precision. Learn to reduce your task to be practical in the chip....
Then your adc setting is wrong. ADC_CLOCK_INTERNAL, is not recommended above 1MHz, unless you stop the chip to take teh reading. Look at the data sheet.
Generally most LCD's need some delay before starting. The PIC will start to run before the LCD has actually started. Put some extra delay at the start of the code before trying to wake the LCD, or you are likely to find this unreliable.
Then there are some 'insanities' in your code. You take an integer, and convert this to a float value ((double)(now - lastTime)). Ugh. Stick to integers.

Then for your question, look at the CCS #USE TIMER. and it's associated functions. In particular get_ticks. Millis is not a generic function (pretty much only exists for the Arduino). Get_ticks, in it's standard form is equivalent to the Arduino 'micros' function. However you can reprogram the #use to work in mSec if you require, and then get_ticks would be equivalent to get_millis.
temtronic



Joined: 01 Jul 2010
Posts: 9163
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Nov 14, 2016 6:03 am     Reply with quote

couple of comments regarding...
Quote:
Temp=read_adc()*5000.0/1024.0;

Floating point division takes 'forever' on a PIC. It is better to just do
Temp=read_adc()*4.88 IF you use floating point, though using all integer math IS the way to go...

Also "5000.0" looks like you're using VDD as the Vref. If this is true, please note that VDD is NOT stable enough for Vref, it's also NOT 5.000 volts AND WILL vary depending on the current demands. Whenever an I/O pin it turned on,the VDD will drop. When doing 'calculations' as opposed to being idle, the VDD will drop.

You also talk about an 'oven control', this implies a high current relay and that WILL drop VDD and/or induce EMI spikes onto VDD. Since you're using VDD as Vref, Vref WILL 'see' higher of lower voltages so the ADC will not report the real Vin.

It's best to
1) use a stable voltage reference device for Vref
2) sample 16* then take average(fast with a PIC)
3) use a LOT of bypass caps on the PCB
4) use heavy Vdd and Gnds on the PCB
5) use R-C-R-C filter for the temp sensor input to PCB.

Jay
emelyjose



Joined: 13 Nov 2016
Posts: 5

View user's profile Send private message

PostPosted: Mon Nov 14, 2016 4:49 pm     Reply with quote

Hi, thanks for your comments and the tips that you are giving me, I will take them into account. As I said this is an original code for Arduino and I I am in the process of migrating it to CCS.

But my main question is how do I measure the instructional time of the program from start to finish ?

If you could give me an example of how to do it. The rest of the code I am adjusting as I organize.

Function millis() of Arduino, migrated to CCS pic - how it is performed ? Please help me.
temtronic



Joined: 01 Jul 2010
Posts: 9163
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Nov 14, 2016 5:58 pm     Reply with quote

I'm not to sure how or why you want the ardunio function millis(). It only shows how long a program has run for since the PIC was started. It should be easy to setup a timer and 'emulate' the millis() function, I'm just at a loss to understand what benefit it is.
A PID controller doesn't need it !

However I'm thinking now, perhaps you may want to know how long the PIC has turned on the heater vs off time?

Jay
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Tue Nov 15, 2016 3:05 am     Reply with quote

Why?

Please tell us what you want time in ms for, and the required precision.

Mike
emelyjose



Joined: 13 Nov 2016
Posts: 5

View user's profile Send private message

PostPosted: Tue Nov 15, 2016 6:59 am     Reply with quote

I need to implement the millis() Arduino function in ccs to get the time it takes to run the program from the beginning to the endl in milliseconds and save this time in a variable.
temtronic



Joined: 01 Jul 2010
Posts: 9163
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Tue Nov 15, 2016 12:22 pm     Reply with quote

OK, have a look at the 'stopwatch' program that CCS supplies in the examples folder (stwt.c or something like that, I'm going from memory here..)
At the beginning of your program you'll need to 'start' the task, then when your program is done, 'stop' the task, then printout the value stored.
If you setup the timer correctly, each bit will be 1 millisecond......

Jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19338

View user's profile Send private message

PostPosted: Tue Nov 15, 2016 12:35 pm     Reply with quote

As I have already said, #USE TIMER, then 'get_ticks' by default gives a direct equivalent of the Arduino 'micros' function. Divide by 1000, and you have millis. You can also specify the tick in the #USE TIMER setup, so could set this to give 1mSec. However this may not be possible because of the limitations of the hardware timers, so division is easier.
emelyjose



Joined: 13 Nov 2016
Posts: 5

View user's profile Send private message

PostPosted: Wed Nov 16, 2016 1:55 am     Reply with quote

As I said I'm new to programming and I do not know how to implement ticks.

Could give me an example. Thank you.
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Wed Nov 16, 2016 12:24 pm     Reply with quote

emelyjose wrote:
I need to implement the millis() Arduino function in ccs to get the time it takes to run the program from the beginning to the endl in milliseconds and save this time in a variable.

But you are still not telling us why you must have the information.

However to generate 1ms ticks you can:-

1) Set up a spare timer to generate an interrupt every 1ms.
2) In the associated ISR you increment a tick_counter.
3) Then at the start of your routine make a note of the tick_counter value.
4) At the end of the routine make second note of the tick_counter value.
5) Perform the subtraction and job's done.

Mike
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Nov 16, 2016 12:47 pm     Reply with quote

He can't do that. He can't write code. His posted code came from here:
http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-sample-time/

That program uses the millis() function, and it doesn't include source for it.
He wants us to write it for him because he can't do it. That's the whole story.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group