|
|
View previous topic :: View next topic |
Author |
Message |
Harry Mueller
Joined: 17 Oct 2005 Posts: 116
|
minus signs not showing up consistently in printf |
Posted: Fri Apr 21, 2006 6:39 am |
|
|
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
|
|
Posted: Fri Apr 21, 2006 8:23 am |
|
|
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
|
|
Posted: Fri Apr 21, 2006 8:25 am |
|
|
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
|
|
Posted: Fri Apr 21, 2006 9:40 am |
|
|
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
|
|
Posted: Fri Apr 21, 2006 9:44 am |
|
|
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
|
|
Posted: Fri Apr 21, 2006 12:28 pm |
|
|
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
|
|
Posted: Fri Apr 21, 2006 2:30 pm |
|
|
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 |
|
|
|
|
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
|