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 CCS Technical Support

Help with clocking code
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

Help with clocking code
PostPosted: Tue Feb 17, 2015 5:04 pm     Reply with quote

Hi Folks,

I wrote the following code in order to get custom clock for general use (LCD display update, etc.) I usually use both (pulse & rise edge pulse).

My question is: is that the best way in terms of CPU scan? Any other better way to get the same result?

Sorry, I'm not expert in the C language, so any help would be appreciated!

PS. I'm using CCS C 5.042

Thanks
Hugo

Code:

#include <18f2550.h>
#device ICD = TRUE
#device ADC=10               
#use delay (clock=48000000)
#fuses HSPLL,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,USBDIV,PLL5,CPUDIV1,DEBUG

void Initialization() {
//Disable all interrupts
   disable_interrupts(GLOBAL);
//Configure Timer1 - Configura Timer1
   setup_timer_1 (T1_INTERNAL | T1_DIV_BY_8); //Configures timer1
   enable_interrupts(INT_TIMER1); //Enable Timer1 interrupt
//Set AD for Internal Clock
   setup_adc(ADC_CLOCK_INTERNAL);
//Set GIE&PEIE bits and Enable all interrupts
   enable_interrupts(GLOBAL);
 }
 
// =============================================================
// "Timer1", interrupt every 10ms
// =============================================================
int1 Pulse_50ms=0;     
int1 Pulse_100ms=0;     
int1 Pulse_200ms=0;   
int1 Pulse_500ms=0;     
int1 Pulse_1000ms=0; 
#INT_TIMER1         
void timer1()         
  {
  static int8 Counter50=3;
  static int8 Counter100=0;
  static int8 Counter500=1;
 
      set_timer1(50536 + get_timer1()); //10ms @ 48 MHz
         
//50ms Clock generator
    Counter50++;
       if (Counter50==5) Pulse_50ms=!Pulse_50ms, Counter50=0;     
//100ms&200ms Clock generator
    Counter100++;
       if (Counter100==10) Pulse_100ms=1;
       if (Counter100==20)
       {
       Pulse_200ms=!Pulse_200ms;
       Pulse_100ms=0;
       Counter100=0;
       }
//500ms&1s Clock generator
    Counter500++;
       if (Counter500==50) Pulse_500ms=1;
       if (Counter500==100)
       {
       Pulse_1000ms=!Pulse_1000ms;
       Pulse_500ms=0;
       Counter500=0;
       }
 }
 
// =============================================================
// "One Shot Rising, OSR", Generates rising edge pulse every 50ms
// =============================================================
int1 Edge_50ms; 
void Function_Edge_50ms() //Function declaration
{
static int1 aux50;     //Auxiliar Variable
   if (Pulse_50ms) //If pulse is true
      { 
         if (aux50==0) Edge_50ms=1; else Edge_50ms=0; //and aux50 is false then Edge_50ms=TRUE for only one scan
         aux50=1; //Next scan Edge_50ms will be false
      }
      else aux50=0; //Clear aux50 till next rising edge detection
}
// *************************************************************
// =============================================================
// "One Shot Rising, OSR", Generates rising edge pulse every 100ms
// =============================================================
int1 Edge_100ms; 
void Function_Edge_100ms() //Function declaration
{
static int1 aux100; //Auxiliar Variable
   if (Pulse_100ms) //If pulse is true
      { 
         if (aux100==0) Edge_100ms=1; else Edge_100ms=0; //and aux100 is false then Edge_100ms=TRUE for only one scan
         aux100=1; //Next scan Edge_100ms will be false
      }
      else aux100=0; //Clear aux100 till next rising edge detection
}
// *************************************************************
// =============================================================
// "One Shot Rising, OSR", Generates rising edge pulse every 200ms
// =============================================================
int1 Edge_200ms;
void Function_Edge_200ms() //Function declaration
{
static int1 aux200; //Auxiliar Variable
   if (Pulse_200ms) //If pulse is true
      { 
         if (aux200==0) Edge_200ms=1; else Edge_200ms=0; //and aux200 is false then Edge_200ms=TRUE for only one scan
         aux200=1; //Next scan Edge_200ms will be false
      }
      else aux200=0; //Clear aux200 till next rising edge detection
}
// *************************************************************
// =============================================================
// "One Shot Rising, OSR", Generates rising edge pulse every 500ms
// =============================================================
int1 Edge_500ms; 
void Function_Edge_500ms() //Function declaration
{
static int1 aux500; //Auxiliar Variable
   if (Pulse_500ms) //If pulse is true
      { 
         if (aux500==0) Edge_500ms=1; else Edge_500ms=0; //and aux500 is false then Edge_500ms=TRUE for only one scan
         aux500=1; //Next scan Edge_500ms will be false
      }
      else aux500=0; //Clear aux500 till next rising edge detection
}
// *************************************************************
// =============================================================
// "One Shot Rising, OSR", Generates rising edge pulse every 1000ms
// =============================================================
int1 Edge_1000ms;
void Function_Edge_1000ms() //Function declaration
{
static int1 aux1000; //Auxiliar Variable
   if (Pulse_1000ms) //If pulse is true
      { 
         if (aux1000==0) Edge_1000ms=1; else Edge_1000ms=0; //and aux1000 is false then Edge_1000ms=TRUE for only one scan
         aux1000=1; //Next scan Edge_1000ms will be false
      }
      else aux1000=0; //Clear aux500 till next rising edge detection
}
// *************************************************************

void Main() {

Unsigned int16 Temp0=0;
int1 Temp1=0;

  Initialization();
   while(1){

  Function_Edge_50ms(); 
  Function_Edge_100ms();
  Function_Edge_200ms();
  Function_Edge_500ms();
  Function_Edge_1000ms();
 
  if (Edge_500ms) Temp0++; // increment temp0 by 1 every 1s
  if (Pulse_500ms) Temp1=1; else Temp1=0; // 500ms blinking bool
 
  //if (Edge_100ms) printf(LCD_PUTC,"%4ld %1lu",Temp0,Temp1); //display every 100ms
         }
}
//------------------ EOF ---------------------

_________________
Hugo Silva


Last edited by younder on Mon Feb 23, 2015 6:48 pm; edited 2 times in total
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

PostPosted: Wed Feb 18, 2015 4:26 pm     Reply with quote

Any expert to help me with my poor code?
_________________
Hugo Silva
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Wed Feb 18, 2015 5:26 pm     Reply with quote

you need to post a compilable program -showing all the stuff affects timers
-setup-master osc frequency- in fact all the stuff mentioned in:

http://www.ccsinfo.com/forum/viewtopic.php?t=26245

what you post is not nearly enough to know what you are trying to do
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

PostPosted: Wed Feb 18, 2015 6:52 pm     Reply with quote

Thanks for your reply...

I've just prepared an example code, so that you can compile and test it.

Code:

#include <18f2550.h>
#device ICD = TRUE
#device ADC=10               
#use delay (clock=48000000)
#fuses HSPLL,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,USBDIV,PLL5,CPUDIV1,DEBUG

void Initialization() {
//Disable all interrupts
   disable_interrupts(GLOBAL);
//Configure Timer1 - Configura Timer1
   setup_timer_1 (T1_INTERNAL | T1_DIV_BY_8); //Configures timer1
   enable_interrupts(INT_TIMER1); //Enable Timer1 interrupt
//Set AD for Internal Clock
   setup_adc(ADC_CLOCK_INTERNAL);
//Set GIE&PEIE bits and Enable all interrupts
   enable_interrupts(GLOBAL);
 }
 
// =============================================================
// "Timer1", interrupt every 10ms
// =============================================================
int1 Pulse_50ms=0;     
int1 Pulse_100ms=0;     
int1 Pulse_200ms=0;   
int1 Pulse_500ms=0;     
int1 Pulse_1000ms=0; 
#INT_TIMER1         
void timer1()         
  {
  static int8 Counter50=3;
  static int8 Counter100=0;
  static int8 Counter500=1;
 
      set_timer1(50536 + get_timer1()); //10ms @ 48 MHz
         
//50ms Clock generator
    Counter50++;
       if (Counter50==5) Pulse_50ms=!Pulse_50ms, Counter50=0;     
//100ms&200ms Clock generator
    Counter100++;
       if (Counter100==10) Pulse_100ms=1;
       if (Counter100==20)
       {
       Pulse_200ms=!Pulse_200ms;
       Pulse_100ms=0;
       Counter100=0;
       }
//500ms&1s Clock generator
    Counter500++;
       if (Counter500==50) Pulse_500ms=1;
       if (Counter500==100)
       {
       Pulse_1000ms=!Pulse_1000ms;
       Pulse_500ms=0;
       Counter500=0;
       }
 }
 
// =============================================================
// "One Shot Rising, OSR", Generates rising edge pulse every 50ms
// =============================================================
int1 Edge_50ms; 
void Function_Edge_50ms() //Function declaration
{
static int1 aux50;     //Auxiliar Variable
   if (Pulse_50ms) //If pulse is true
      { 
         if (aux50==0) Edge_50ms=1; else Edge_50ms=0; //and aux50 is false then Edge_50ms=TRUE for only one scan
         aux50=1; //Next scan Edge_50ms will be false
      }
      else aux50=0; //Clear aux50 till next rising edge detection
}
// *************************************************************
// =============================================================
// "One Shot Rising, OSR", Generates rising edge pulse every 100ms
// =============================================================
int1 Edge_100ms; 
void Function_Edge_100ms() //Function declaration
{
static int1 aux100; //Auxiliar Variable
   if (Pulse_100ms) //If pulse is true
      { 
         if (aux100==0) Edge_100ms=1; else Edge_100ms=0; //and aux100 is false then Edge_100ms=TRUE for only one scan
         aux100=1; //Next scan Edge_100ms will be false
      }
      else aux100=0; //Clear aux100 till next rising edge detection
}
// *************************************************************
// =============================================================
// "One Shot Rising, OSR", Generates rising edge pulse every 200ms
// =============================================================
int1 Edge_200ms;
void Function_Edge_200ms() //Function declaration
{
static int1 aux200; //Auxiliar Variable
   if (Pulse_200ms) //If pulse is true
      { 
         if (aux200==0) Edge_200ms=1; else Edge_200ms=0; //and aux200 is false then Edge_200ms=TRUE for only one scan
         aux200=1; //Next scan Edge_200ms will be false
      }
      else aux200=0; //Clear aux200 till next rising edge detection
}
// *************************************************************
// =============================================================
// "One Shot Rising, OSR", Generates rising edge pulse every 500ms
// =============================================================
int1 Edge_500ms; 
void Function_Edge_500ms() //Function declaration
{
static int1 aux500; //Auxiliar Variable
   if (Pulse_500ms) //If pulse is true
      { 
         if (aux500==0) Edge_500ms=1; else Edge_500ms=0; //and aux500 is false then Edge_500ms=TRUE for only one scan
         aux500=1; //Next scan Edge_500ms will be false
      }
      else aux500=0; //Clear aux500 till next rising edge detection
}
// *************************************************************
// =============================================================
// "One Shot Rising, OSR", Generates rising edge pulse every 1000ms
// =============================================================
int1 Edge_1000ms;
void Function_Edge_1000ms() //Function declaration
{
static int1 aux1000; //Auxiliar Variable
   if (Pulse_1000ms) //If pulse is true
      { 
         if (aux1000==0) Edge_1000ms=1; else Edge_1000ms=0; //and aux1000 is false then Edge_1000ms=TRUE for only one scan
         aux1000=1; //Next scan Edge_1000ms will be false
      }
      else aux1000=0; //Clear aux500 till next rising edge detection
}
// *************************************************************

void Main() {

Unsigned int16 Temp0=0;
int1 Temp1=0;

  Initialization();
   while(1){

  Function_Edge_50ms(); 
  Function_Edge_100ms();
  Function_Edge_200ms();
  Function_Edge_500ms();
  Function_Edge_1000ms();
 
  if (Edge_500ms) Temp0++; // increment temp0 by 1 every 1s
  if (Pulse_500ms) Temp1=1; else Temp1=0; // 500ms blinking bool
 
  //if (Edge_100ms) printf(LCD_PUTC,"%4ld %1lu",Temp0,Temp1); //display every 100ms
         }
}
//------------------ EOF ---------------------

_________________
Hugo Silva
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Wed Feb 18, 2015 7:07 pm     Reply with quote

Does it work up to expectations now?

Is there a specific concern about execution improvement?
Ttelmah



Joined: 11 Mar 2010
Posts: 19518

View user's profile Send private message

PostPosted: Thu Feb 19, 2015 1:56 am     Reply with quote

1) Is ADC_CLOCK_INTERNAL recommended on a chip at 48MHz?. Read the data sheet. This is a common fault, and will massively degrade the ADC performance....
2) Seems very complex. What I can't see is what you are actually doing?. There is no pin being controlled or pulse patterns generated for all this work. Presumably omitted from the example?.
I'd suspect it'd be much simpler to draw a table of what pins want to operate when, then convert this into an array of bit patterns, corresponding to times. Then have a simple one counter state machine walking through the array and outputting the required pattern.
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

PostPosted: Thu Feb 19, 2015 6:54 pm     Reply with quote

asmboy wrote:
Does it work up to expectations now?

Is there a specific concern about execution improvement?


I use the posted code in most of my codes...the main concern I have is regarding the particular scan in where for example, the rise edge 50ms is being used for call many functions or even do some math...display at LCD etc. I Also was wondering if the way I'm generating the flags inside the ISR is most appropriate way in terms of processing.
_________________
Hugo Silva
Ttelmah



Joined: 11 Mar 2010
Posts: 19518

View user's profile Send private message

PostPosted: Fri Feb 20, 2015 2:24 am     Reply with quote

As I said, a table.

Not 'right' you'll have to adjust rates and starting points to get what you actually want, but something like:
Code:

int8 counts[] = {5,10,20,50,100};
union {
   int8 mask;
   struct {
      int1 MS_50;
      int1 MS_100;
      int1 MS_200;
      int1 MS_500;
      int1 MA_1000;
   } pulse;
}
#INT_TIMER1             // Definition that next line will be associated to Timer1 interrupt - linha que define que a próxima função será associada à interrupção do TIMER1
void timer1(void)           // Function called automaticaly every 100ms - esta função não precisará ser chamada. Será executada automaticamente.
{
  static int8 counters[5] = {3,1,1,1,1};
  int8 ctr;
  int8 mask=1;
  set_timer1(50536 + get_timer1()); //15000 counts
  for (ctr=0;ctr<5;ctr++)
  {
     --counter[ctr];
     if (counters[ctr]==0)
     {
        counters[ctr]=counts[ctr];
        pulse.mask ^= mask;
     }
     mask*=2;
  }
}

Then pulse.MS_50 toggles every 50mSec, pulse.MS_100, every 100 etc...

However there seems something wrong with the times you say, since the interrupt is every 10mSec, not the 100 you refer to....

As a comment, why interrupt this fast?. The slowest 'tick' you are using is 50mSec, Now with the divider you are using, you can't make the interrupt tick at this rate, but you could make it tick at 25mSec easily, and this then reduces the CPU time in the interrupt by an enormous amount....

Switch to 37500 counts from the current 15000, and change the count values to 2,4,8,20,40. This would take the CPU time down to under 0.5* straight away..... Never 'tick' faster than you really need!.
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

PostPosted: Sat Feb 21, 2015 2:17 pm     Reply with quote

I appreciate your proposed code Ttelmah, nothing like ideas from different point of views! So what you are saying is that, a for loop and the showed table would take much less time inside the ISR than all those if's?

Do you think that it would be possible to generate the "one scan toggle flags" inside the ISR? I understand that there will be lots of scans between the overflows...but I would be able to at least set the Edge_50ms flag inside the ISR and then reset it somewhere else, am I right?
_________________
Hugo Silva
Ttelmah



Joined: 11 Mar 2010
Posts: 19518

View user's profile Send private message

PostPosted: Sat Feb 21, 2015 2:46 pm     Reply with quote

The thing that would make the biggest difference to timing, would be to reduce the interrupt rate. Since your quickest event is 5 counts, going down to 1/2.5 the interrupt rate would save a huge amount of time.
The code wouldn't be very different on performance. If's are efficient, but it'd be much easier to change times, and keep track of what is meant to happen 'when', with the table.
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

PostPosted: Mon Feb 23, 2015 6:56 pm     Reply with quote

Ttelmah wrote:

However there seems something wrong with the times you say, since the interrupt is every 10mSec, not the 100 you refer to....


I`ve corrected the code posted on post #1...comment was wrong...code was right...

Ttelmah, In relation to the edges...do you believe is it ok? sorry for my questions...but I know you always come up with nice suggestions/comments.

Ttelmah wrote:
1)
2) Seems very complex. What I can't see is what you are actually doing?. There is no pin being controlled or pulse patterns generated for all this work. Presumably omitted from the example?.
.

I use the pulses/edges by scanning them on main loop to perform different tasks at the respective rates, as shown in the example below...

Code:

void Main() {

Unsigned int16 Temp0=0;
int1 Temp1=0;

  Initialization();
   while(1){

  Function_Edge_50ms();  //Generate edge pulses
  Function_Edge_100ms();
  Function_Edge_200ms();
  Function_Edge_500ms();
  Function_Edge_1000ms();

  if (Edge_50ms) read_AD(0); //Read AD0 every 50ms
 
  if (Edge_500ms) Temp0++; // increment temp0 by 1 every 1s ....
  if (Pulse_500ms) Temp1=1; else Temp1=0; // 500ms blinking bool .... Temp1 could also be an output pin
 
  if (Edge_100ms) printf(LCD_PUTC,"%4ld %1lu",Temp0,Temp1); //display every 100ms thru 100ms edge flag
         }
}


And finnaly,

Ttelmah wrote:
1) Is ADC_CLOCK_INTERNAL recommended on a chip at 48MHz?. Read the data sheet. This is a common fault, and will massively degrade the ADC performance....
.


what would be the recommended on a chip at 48MHz? (I will get a look in the manual...just trying to save some time...) Very Happy Very Happy
_________________
Hugo Silva
Ttelmah



Joined: 11 Mar 2010
Posts: 19518

View user's profile Send private message

PostPosted: Tue Feb 24, 2015 8:33 am     Reply with quote

_Data sheet_. Even has a table showing the recommended values for different clock rates. _Compulsory reading_.
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

PostPosted: Tue Feb 24, 2015 5:59 pm     Reply with quote

Ttelmah wrote:
_Data sheet_. Even has a table showing the recommended values for different clock rates. _Compulsory reading_.


you're right Ttelmah, it is just a common mistake not read the DATA SHEET!Very Happy

Off topic: TABLE 21-1 says 64 TOSC for Maximum Device Frequency = 48.0 MHz, so in that case, should I declare?:

Code:
 setup_adc(ADC_CLOCK_DIV_64 | ADC_TAD_MUL_0);


"Not sure"about second part ADC_TAD_MUL_0...

Also did not understand the table 21-1 - Note 3: (which is related to the Internal RC Oscillator option):
Quote:

For device frequencies above 1 MHz, the device must be in Sleep for the entire conversion or the A/D
accuracy may be out of specification.


Is it applicable only if I use...?
Code:

setup_adc(ADC_CLOCK_INTERNAL);


Thanks Ttelmah
_________________
Hugo Silva
Ttelmah



Joined: 11 Mar 2010
Posts: 19518

View user's profile Send private message

PostPosted: Wed Feb 25, 2015 1:24 am     Reply with quote

Spot on. Yes, only with the internal RC oscillator.

The TAD_MUL option, allows you to program the chip to automatically pause after you requests a reading, for the signal to acquire.

The standard ADC, when you start it, just starts the reading straight away. This is why if you change the ADC channel, or repeat readings one after the other, you have to have a delay before the reading. This allows the internal capacitor to charge to the actual voltage on the pin.
On this (and most similar modern ADC's), you can program the ADC to automatically add this delay. This is the TAD_MUL option. It pauses for the programmed number of Tad cycles, with the pin connected to the capacitor, and only after this time has passed, actually starts the reading. You need this if using the DMA to perform a fast sequence of readings, or if you are triggering the reading from an 'event' like the PWM, and you need to ensure that acquisition takes place after the event, before you actually read.
If the channel is already selected, and there is enough time between the readings, you can leave this delay at '0', otherwise it just slows down the actual ADC operation.
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

PostPosted: Wed Feb 25, 2015 9:50 am     Reply with quote

Great clarification!

21.3 says that the A/D conversion requires 11 TAD per 10-bit conversion as well as for a correct A/D conversion, the A/D conversion clock
(TAD) must be as short as possible but greater than the minimum TAD. TABLE 28-29 refers to a minimum of 0.7us and maximum of 25.0us (Tosc based & Vref>=3.0V). So, how to define the correct TAD time considering that I'm using multiple channels and accuracy/high speed reading is needed ?

Quote:

(ADCON2)
bit 5-3 ACQT2:ACQT0: A/D Acquisition Time Select bits
111 = 20 TAD
110 = 16 TAD
101 = 12 TAD
100 = 8 TAD
011 = 6 TAD
010 = 4 TAD
001 = 2 TAD
000 = 0 TAD

_________________
Hugo Silva
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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