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

minus signs not showing up consistently in printf

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



Joined: 17 Oct 2005
Posts: 116

View user's profile Send private message

minus signs not showing up consistently in printf
PostPosted: Fri Apr 21, 2006 6:39 am     Reply with quote

In a debugging exercise I print out 3 variables. The calculations are all done correctly but two of the printed values, Accel_percent and Avg may or may not show a minus sign, it seems almost arbitrary. The value Acceleration , a value between +10,000 and -10,000 always shows the proper sign.

Here are the three printf statements:

Code:
    printf("\r\nAcceleration = %ld", accel_value);
    printf("\r\nAccel_percent = %4ld.%02ld", accel_value/100, accel_value%100);
    printf("\r\nAvg= %4ld.%02ld",running_av_accel/100, running_av_accel%100);

Any idea why this is happening and how it can be corrected?

Thanks, Harry
Ttelmah
Guest







PostPosted: Fri Apr 21, 2006 8:23 am     Reply with quote

What compiler version?.
There was a bug that applied to a few versions, where if the 'carry' flag is set from one arithmetic operation, it incorrectly gets displayed as a 'sign', in printf...
If you do the arithmetic 'outside' the printf, it doesn't happen. Also consider that if you have a reasonably recent compiler, you could use %w instead of doing the splitting yourself. Also, look at ldiv.

Best Wishes
SherpaDoug



Joined: 07 Sep 2003
Posts: 1640
Location: Cape Cod Mass USA

View user's profile Send private message

PostPosted: Fri Apr 21, 2006 8:25 am     Reply with quote

Can you show us the declarations for these variables and the math that calculates them? I suspect somewhere you are using an unsigned type to hold a signed value.
_________________
The search for better is endless. Instead simply find very good and get the job done.
Harry Mueller



Joined: 17 Oct 2005
Posts: 116

View user's profile Send private message

PostPosted: Fri Apr 21, 2006 9:40 am     Reply with quote

Ttelmah wrote:
What compiler version?.
There was a bug that applied to a few versions, where if the 'carry' flag is set from one arithmetic operation, it incorrectly gets displayed as a 'sign', in printf...
If you do the arithmetic 'outside' the printf, it doesn't happen. Also consider that if you have a reasonably recent compiler, you could use %w instead of doing the splitting yourself. Also, look at ldiv.

Best Wishes


My compiler version is 3.245. I will try using %w to see if that clears it up, however I would really like to know what is causing my problem just to learn more.

What is ldiv?

Thanks, Harry
Harry Mueller



Joined: 17 Oct 2005
Posts: 116

View user's profile Send private message

PostPosted: Fri Apr 21, 2006 9:44 am     Reply with quote

SherpaDoug wrote:
Can you show us the declarations for these variables and the math that calculates them? I suspect somewhere you are using an unsigned type to hold a signed value.


I don't think I've done that but maybe I've missed something. Here is all my code....hope it's not too long to go through.
Code:
//This program computes acceleration and rate of change with an accelerometer
// and a gyro and uses these values to calculate torque for the DC motors.
// It uses an interrupt on port_b for both calculations.


#include <16F877.H>
#include <24256-1.c>
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 20000000)
#use RS232(BAUD=38400,XMIT=PIN_C6,RCV=PIN_C7)//communication link with BotLoader

//raise this value as high as you can without overflowing the math
#define ADXL202_SCALING_FACTOR 100000

#define motor_fwd 0b00000011
#define motor_rev 0b11111100

//global vars...................................................................

int current_portb, delta_portb, count;
signed int16 running_av_accel, gyro_value;
unsigned int16 accel_period, accel_pulse, reading, adxl_ppg;
unsigned int16 accel_value_address, gyro_pulse, last_gyro_pulse;
signed int32 adxl_zerog;
static int8 index = 0, flag = 0;
static int last_portb;
static unsigned int16 accel_old_reading, gyro_old_reading;

//Initialization routines.......................................................

void motor_init()
 {
  int8 torque;
  int1 flag=0;
  //port_b_pullups(TRUE);                           // ????
  setup_timer_2(T2_DIV_BY_1,199, 1);                // 25 KHz
  setup_ccp1(CCP_PWM);                              // Configure CCP1 as a PWM
  setup_ccp2(CCP_PWM);                              // Configure CCP2 as a PWM
 }

void accelerometer_init(unsigned int32 zerog, long ppg)
{
   adxl_zerog=zerog;
   adxl_ppg=ppg;
   setup_timer_0 (RTCC_INTERNAL | RTCC_DIV_32);
   setup_timer_1 (T1_INTERNAL);
   enable_interrupts(INT_RTCC);
   enable_interrupts(INT_RB);
   enable_interrupts(GLOBAL);
}

//Interrupts service routines...................................................

#int_RTCC                                            // Output 1500 uS pulse
Gyro_input_isr()
{
 set_timer0(22);
 if (++count==12)
 count = 0;
 else
 {
 if(count<2)
 output_high(PIN_E2);
 else
 output_low(PIN_E2);
 }
}

#int_RB

void accel_gyro_isr(void)
{
reading = get_timer1();                              //Read Timer_1
current_portb = input_b();                           //Read value of PORT_B
delta_portb = (current_portb ^ last_portb) >> 4;     //Did PORT_B change?
last_portb = current_portb;                          //Remember PORT_B value
if ((delta_portb == 0x08) ||
    (delta_portb == 0x0c))                           //If PIN_B7 has changed
 {
  if (bit_test(current_portb, 7))                    //If PIN_B7 is high
  {
   accel_period = reading - accel_old_reading;       //Calculate period
   accel_old_reading = reading;
  }
  else
   accel_pulse = reading - accel_old_reading;         //Calculate duty
 }
  else if ((delta_portb == 0x02) ||
            (delta_portb == 0x06) ||
             (delta_portb == 0x0a) ||
              (delta_portb == 0x0e) ||
               (delta_portb == 0x0f))
   {
    if (bit_test(current_portb, 5))                  //If PIN_B5 is high
     gyro_old_reading = reading;                     // Record timer_1 reading
    else
     gyro_pulse = reading - gyro_old_reading;        //Calculate gyro_pulse
   }
 }

//Functions.....................................................................

// A(g) = (T1/T2 - 0.456) / 0.118
// 0g = 50% duty cycle
signed int16 accelerometer_read(void)
{
 signed int32 value;
 value = accel_pulse * ADXL202_SCALING_FACTOR;
 value = value / accel_period;
 value = value - adxl_zerog;
 value = (value  * 10000) / adxl_ppg;
 return(value);
}

signed int16 gyro_read(void)
{
 signed int32 value;
 value = (gyro_pulse / 5) - 1500;                // Covert ticks to change in uS
 return(value);
}

signed int16 running_average(signed int16 add_value)
 {
    static signed int16 vals[6], sum;
    signed int16 result;
    if ((index==0) && (flag == 0)) //discard phoney first value
    add_value = 0;
    if (flag==5)                 // continue once five values have been received
    {
     sum += add_value;
     sum -= vals[index];
     vals[index] = add_value;
     result = sum / 5;
     index = (index+1) % 5;
     flag = 5;
     return(result);
    }
    else                         //fill up the first 5 values and calculate sum
    {
     vals[index] = add_value;
     sum += add_value;
     result = sum / ++index;     
     if (index==5)
     index = 0;
     flag++;
     return(result);
    }
 }

motor_control()
{
 int16 K_accel = 1, K_gyro = 1;
 signed int16 torque = 0;
 torque = ((running_av_accel/100) * K_accel) +
           (gyro_value * K_gyro);
 //printf("\n\rMotor_control section.............................");
 //printf("\r\nrunning_av_accel = %ld ",running_av_accel/100);
 //printf("\r\ngyro_value = %ld ",gyro_value);
 //printf("\r\nTorque = %ld ",torque);
 i2c_start();
 i2c_write(0x40);
 if ((torque > 50) || (torque < (-50)))
 {
 if (torque > 0)
  i2c_write(0b00000011);
 else
  i2c_write(0b11111100);
 i2c_stop();
 set_pwm1_duty(4*abs(torque));            // calculated duty cycle on pin B2
 set_pwm2_duty(4*abs(torque));            // calculated duty cycle on pin B1
 }
  else;
}

//Main program..................................................................

main()
{
 accelerometer_init(45600,11750);         //calibrated values
 init_ext_eeprom();                       // initialize external EEPROM
 motor_init();                            // initialize motors
 {
  while (1)
   {
    signed int16 accel_value;
    accel_value = accelerometer_read();// "Value" varies from -10,000 to +10,000
    //write_ext_eeprom(accel_value_address, accel_value);
    running_av_accel = running_average(accel_value);
    gyro_value = gyro_read();
    motor_control();
    printf("\n\rMain section.................................................");
    printf("\r\nGyro rate of change = %ld%%",gyro_value);
    printf("\r\nAcceleration = %ld", accel_value);
    printf("\r\nAccel_percent = %4ld.%02ld", accel_value/100, accel_value%100);
    printf("\r\nAvg Acelleration = %4ld.%02ld",running_av_accel/100, running_av_accel%100);
    delay_ms(250);
   }
 }
}


Thanks, Harry
Harry Mueller



Joined: 17 Oct 2005
Posts: 116

View user's profile Send private message

PostPosted: Fri Apr 21, 2006 12:28 pm     Reply with quote

Harry Mueller wrote:
Ttelmah wrote:
What compiler version?.
There was a bug that applied to a few versions, where if the 'carry' flag is set from one arithmetic operation, it incorrectly gets displayed as a 'sign', in printf...
If you do the arithmetic 'outside' the printf, it doesn't happen. Also consider that if you have a reasonably recent compiler, you could use %w instead of doing the splitting yourself. Also, look at ldiv.

Best Wishes


My compiler version is 3.245. I will try using %w to see if that clears it up, however I would really like to know what is causing my problem just to learn more.

What is ldiv?

Thanks, Harry


I used the %W format and it cleared the problem up. Thanks, Ttelmah, I didn't even know that existed.

Harry
Ttelmah
Guest







PostPosted: Fri Apr 21, 2006 2:30 pm     Reply with quote

The 'sign bug', was posted about a few weeks ago, with another poster performing arithmetic inside the printf, and getting similar behaviour. If I remember at the time, somebody posted the assembler listing being generated for the arithmetic. If the arithmetic is done outside the printf (put into a variable), it doesn't happen.
Glad %w at least solved the 'effect'. :-)

Best Wishes
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