|
|
View previous topic :: View next topic |
Author |
Message |
younder
Joined: 24 Jan 2013 Posts: 53 Location: Brazil
|
Help with clocking code |
Posted: Tue Feb 17, 2015 5:04 pm |
|
|
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
|
|
Posted: Wed Feb 18, 2015 4:26 pm |
|
|
Any expert to help me with my poor code? _________________ Hugo Silva |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Wed Feb 18, 2015 5:26 pm |
|
|
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
|
|
Posted: Wed Feb 18, 2015 6:52 pm |
|
|
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
|
|
Posted: Wed Feb 18, 2015 7:07 pm |
|
|
Does it work up to expectations now?
Is there a specific concern about execution improvement? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19546
|
|
Posted: Thu Feb 19, 2015 1:56 am |
|
|
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
|
|
Posted: Thu Feb 19, 2015 6:54 pm |
|
|
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: 19546
|
|
Posted: Fri Feb 20, 2015 2:24 am |
|
|
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
|
|
Posted: Sat Feb 21, 2015 2:17 pm |
|
|
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: 19546
|
|
Posted: Sat Feb 21, 2015 2:46 pm |
|
|
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
|
|
Posted: Mon Feb 23, 2015 6:56 pm |
|
|
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...) _________________ Hugo Silva |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19546
|
|
Posted: Tue Feb 24, 2015 8:33 am |
|
|
_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
|
|
Posted: Tue Feb 24, 2015 5:59 pm |
|
|
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!
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: 19546
|
|
Posted: Wed Feb 25, 2015 1:24 am |
|
|
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
|
|
Posted: Wed Feb 25, 2015 9:50 am |
|
|
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 |
|
|
|
|
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
|