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

#define math

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



Joined: 08 Jul 2009
Posts: 24

View user's profile Send private message

#define math
PostPosted: Tue Jul 21, 2009 10:31 pm     Reply with quote

I'm attempting to do some integer math using #define's and am having trouble getting the expected results. I'm reading a pot and using the delay_ms() as a way of testing the result. MPLAB Sim might be a better way to verify. I'm expecting a result of 2000 to 12000, depending on the ADC counts. This should yield a delay of that number of mSec.

Code:

#include <16F526.h>
#device ADC=8
#device *=8 //needed to keep from running out of ram during compile
.
.
.
#define   VAR_MIN   2   ;in seconds
#define   VAR_MAX   12

#define   VAR_SPAN         VAR_MAX - VAR_MIN  ;VAR_SPAN = 10 in this example
#define   VAR_SPAN_CNT      (VAR_SPAN * 10000) / 255 ;approx 392

.
.
.
unsigned int8 ADC_Value;
unsigned int16 Delay_Time;

.
.
.
ADC_Value = read_adc();

Delay_Time = ((VAR_MIN * 10000) + VAR_SPAN_CNT * ADC_Value) / 10;

unsigned int8 ADC_Value;
unsigned int16 Delay_Time;
.
.
.

; turn on test LED here

delay_ms(Delay_Time);  //should delay between 2000 and 12000 mSec

;turn off test LED

mbradley



Joined: 11 Jul 2009
Posts: 118
Location: California, USA

View user's profile Send private message Visit poster's website

PostPosted: Tue Jul 21, 2009 10:40 pm     Reply with quote

I do not see this line in your code:

// substitue the 40000000 for your clock speed
#use delay(clock=40000000)

The compiler needs to know what the clock rate is so it can create the delays. The delays are software delay routines, and does not use a timer.
dossdev



Joined: 08 Jul 2009
Posts: 24

View user's profile Send private message

PostPosted: Tue Jul 21, 2009 10:51 pm     Reply with quote

I actually do have the clock speed set - just didn't show it (and more) in the code snippit. I've verified the delay_ms() with fixed values and it it correct. Since I posted, I've been running the simulator and playing with different values for the ADC value and have found that the result is correct for ADC value = 0. There appears to be some rollover/under going on - just haven't found out why just yet.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Jul 21, 2009 10:53 pm     Reply with quote

You can debug problems like this if you can display intermediate values.
This can be done with an ICD debugger (with a watch window), or with
a serial port with printf statements. Do you have a debugger ?

Are you using a board that has a MAX232-type chip and DB-9 connector ?
If so, you can connect the board to your PC, and put in a #use rs232()
statement to define the serial port.

If you don't have a MAX232 chip and DB-9 on your board, this thread
explains how you can still add a serial port for debugging purposes:
http://www.ccsinfo.com/forum/viewtopic.php?t=22551
dossdev



Joined: 08 Jul 2009
Posts: 24

View user's profile Send private message

PostPosted: Tue Jul 21, 2009 11:04 pm     Reply with quote

I am using an ICD2, but the '526 requires a debug adapter so I can't trace through the code, etc. I may end up adding a MAX232 and using a sw uart to do printf's. The simulator is actually pretty good for showing what is going on. Not a solution yet, but it looks like the in-line calculation blows up whenever I use the #define values. If I replace them with their numerical equivalents, the result is correct. Now I just have to figure out how to get the #define's to behave.
dossdev



Joined: 08 Jul 2009
Posts: 24

View user's profile Send private message

PostPosted: Tue Jul 21, 2009 11:40 pm     Reply with quote

I've narrowed the problem down to what looks to be an issue with using the ADC variable result versus a fixed ADC value. I've tried all sizes of variables, etc. May be a compiler problem.

Code:

Delay_Time = (20000 + (392 * ADC_Value)) / 10;  //doesn't work for certain ADC values like 255

Delay_Time = (20000 + (392 * 255)) / 10;  //works

PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Jul 21, 2009 11:52 pm     Reply with quote

Do you have the PCM compiler ? If so, create a test program for the
16F877 and run it in the MPLAB simulator. Use the UART1 feature of
MPLAB to display printf values in the Output window. (UART1 requires
a PIC with a hardware UART). The following post explains how to do this:
http://www.ccsinfo.com/forum/viewtopic.php?t=23408&start=1

Math problems with #define values are usually caused by:
1. Lack of parenthesis to force the intended order of math operations.
2. Lack of an 'L' on the end of numerical constants larger than 255.
3. Lack of casting of an expression to an int16 or int32, etc.

Here's an example of a program that displays intermediate values.
This will quickly show you where the problem is.
Code:

#include <16F877.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#define   VAR_MIN   2     //in seconds
#define   VAR_MAX   12

#define   VAR_SPAN         VAR_MAX - VAR_MIN         
#define   VAR_SPAN_CNT     (VAR_SPAN * 10000) / 255 

//=====================================
void main()
{
unsigned int8 ADC_Value;
unsigned int16 Delay_Time;

printf("VAR_SPAN = %ld \r", VAR_SPAN);
printf("VAR_SPAN * 10000 = %ld \r", (VAR_SPAN * 10000));
printf("VAR_SPAN_CNT = %ld \r", VAR_SPAN_CNT);

//ADC_Value = read_adc();
ADC_Value = 100;

printf("VAR_MIN * 10000 = %ld \r", VAR_MIN * 10000);
printf("VAR_CNT * ADC_Value = %ld \r", VAR_SPAN_CNT * ADC_Value);
printf("Numerator = %ld \r", (VAR_MIN * 10000) + (VAR_SPAN_CNT * ADC_Value));
Delay_Time = ((VAR_MIN * 10000) + VAR_SPAN_CNT * ADC_Value) / 10;
printf("Delay_Time = %ld \r", Delay_Time);

while(1);
}
Ttelmah
Guest







PostPosted: Wed Jul 22, 2009 2:30 am     Reply with quote

Remember that ';' marks the end of an expression, _not_ a remark.
In the original defines
Code:

#define   VAR_MIN   2   ;in seconds
#define   VAR_MAX   12

#define   VAR_SPAN         VAR_MAX - VAR_MIN  ;VAR_SPAN = 10 in this example
#define   VAR_SPAN_CNT      (VAR_SPAN * 10000) / 255 ;approx 392

I'd actually expect 'VAR_SPAN', to be set to 10, then to get a syntax error for the text 'in this example'. Similarly for the next line.
Correct these, and things may start to give expected values.....

Also, in C, be _very_ careful with bracketting, in defines. '*', has a higher priority than '-', so, if the defines didn't have their incorrect terminating ';', or the remarks, but were:
Code:

#define   VAR_SPAN         VAR_MAX - VAR_MIN
#define   VAR_SPAN_CNT      (VAR_SPAN * 10000) / 255


Then VAR_SPAN_CNT the equation would expand as:

(VAR_MAX - VAR_MIN * 10000)/255

Which will evaluate VAR_MIN * 10000, subtract this from VAR_MAX, then divide the result by 255. Not what is expected I think....

Best Wishes
mbradley



Joined: 11 Jul 2009
Posts: 118
Location: California, USA

View user's profile Send private message Visit poster's website

PostPosted: Wed Jul 22, 2009 3:04 am     Reply with quote

I just now cought this, but it is mentioned above,
Quote:
#define VAR_SPAN VAR_MAX - VAR_MIN ;VAR_SPAN = 10 in this #define VAR_SPAN_CNT (VAR_SPAN * 10000) / 255 ;approx 392

Delay_Time = ((VAR_MIN * 10000) + VAR_SPAN_CNT * ADC_Value) / 10;



perhaps, the paranthesis?
I like to look at defines as a global find and replace.
#define VAR_SPAN ( VAR_MAX - VAR_MIN )
mskala



Joined: 06 Mar 2007
Posts: 100
Location: Massachusetts, USA

View user's profile Send private message

PostPosted: Wed Jul 22, 2009 7:02 am     Reply with quote

Ttelmah wrote:
Remember that ';' marks the end of an expression, _not_ a remark.


I second this remark. You must not use ';' in the #define followed by comment.
andrewg



Joined: 17 Aug 2005
Posts: 316
Location: Perth, Western Australia

View user's profile Send private message Visit poster's website

PostPosted: Wed Jul 22, 2009 7:24 am     Reply with quote

Code:
Delay_Time = (20000 + (392 * ADC_Value)) / 10;  //doesn't work for certain ADC values like 255

392 is an int16, that will promote ADC_Value to be an int16, if it isn't already. The result of the multiplication will also be an int16, which will cause problems for values of ADC_Value greater than 65535/392 = 167.

The solution is to cast 392 or ADC_Value to int32, or to use the CCS _mul() function that automatically expands the size of the result. i.e.

Code:
Delay_Time = (20000 + _mul(392, ADC_Value)) / 10;

_________________
Andrew
dossdev



Joined: 08 Jul 2009
Posts: 24

View user's profile Send private message

PostPosted: Thu Jul 23, 2009 9:29 pm     Reply with quote

Got it all sorted out. My biggest problem was the order of precedence in the #define statements.

Thanks so much for everyone's insightful input.

BR's.
pgin



Joined: 01 Jun 2009
Posts: 1
Location: Canada

View user's profile Send private message

PostPosted: Fri Jul 24, 2009 11:49 pm     Reply with quote

Here is your source code. The errors are fixed and documented.
Code:
#include <16F526.h>
#device ADC=8
#device *=8 //needed to keep from running out of ram during compile
.
.
.
// #define   VAR_MIN   2   ;in seconds
// comment take // In a define using ; is acceptable.  You can do
// #define A   a=2; b=3; c=4;
// The expansion will created 3 assignations.
// If you type A;  The expansion will produced
// a=2; b=3; c=4; ;
// The last semicolumn is the one after the A
#define   VAR_MIN   2   // in seconds
#define   VAR_MAX   12

#define   VAR_SPAN         VAR_MAX - VAR_MIN  ;VAR_SPAN = 10
#define   VAR_SPAN         (VAR_MAX - VAR_MIN)  // VAR_SPAN = 10
// Always put parentesis around expression.  you never know where it will be used.

#define   VAR_SPAN_CNT      (VAR_SPAN * 10000) / 255 ;approx 392
#define   VAR_SPAN_CNT      (((VAR_SPAN) * 10000) / 255) //approx392
// When in a define (macro), you refer to an argument, always put parenthesis around it to avoid wrong evaluation order.
// In your code, you had VA_MAX - VAR_MIN * 10000 / 255
// Evaluation order will be VA_MAX - ( ( VAR_MIN * 10000 ) / 255 )
// Also, in order to have a better accuracy in the computing, you may cast and group the operation.
// Example : If VAR_SPAN happen to contain a variable, then 10000 / 255 will be evaluted immediately.
// #define BAD_ORDER  AAAA    a * 100 / 255 // always 0
// better
// #define GOD_ORDER AAAA    ((a * 100) / 255 )

.
.
.

unsigned int8 ADC_Value;
unsigned int16 Delay_Time;

.
.
.
ADC_Value = read_adc();

// depending on the compiler wou are using and the with of the ADC
// results, chances are that you will have an overflow.
// VAR_MIN * 10000 = 20000, ok for 16-bit
// VAR_SPAN_CNT * ADC_Value : 392 * 256 required 17-bit, you need 24 (available with some DSPs) or 32 bits (with PIC and CCS)...
Delay_Time = ((VAR_MIN * 10000) + VAR_SPAN_CNT * ADC_Value) / 10;
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